1. 程式人生 > >【模板】線段樹(洛谷P3373)

【模板】線段樹(洛谷P3373)

Description

  如題,已知一個數列,你需要進行下面三種操作:

  1.將某區間每一個數乘上x

  2.將某區間每一個數加上x

  3.求出某區間每一個數的和

Input

  第一行包含三個整數N、M、P,分別表示該數列數字的個數、操作的總個數和模數。

  第二行包含N個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

  接下來M行每行包含3或4個整數,表示一個操作,具體如下:

  操作1: 格式:1 x y k 含義:將區間[x,y]內每個數乘上k

  操作2: 格式:2 x y k 含義:將區間[x,y]內每個數加上k

  操作3: 格式:3 x y 含義:輸出區間[x,y]內每個數的和對P取模所得的結果

Output

  輸出包含若干行整數,即為所有操作3的結果。

Solution

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=100000;
long long sum[4*N+10],multag[4*N+10],addtag[4*N+10],a[N+10];
int n,m,Mod,opt,x,y,k;
inline long long read()
{
    long long ans=0,f=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0' && ch<='9')
    {
        ans=ans*10+ch-'0';
        ch=getchar();
    }
    return ans*f;
}
long long mo(long long x,long long y)
{
    return x+y>=Mod?x+y-Mod:x+y;
}
void pushdown(int p,int l,int r)
{
    int mid=(l+r)>>1;
    if (multag[p]!=1)
    {
        sum[p<<1]=sum[p<<1]*multag[p]%Mod;
        sum[p<<1|1]=sum[p<<1|1]*multag[p]%Mod;
        multag[p<<1]=multag[p<<1]*multag[p]%Mod;
        multag[p<<1|1]=multag[p<<1|1]*multag[p]%Mod;
        addtag[p<<1]=addtag[p<<1]*multag[p]%Mod;
        addtag[p<<1|1]=addtag[p<<1|1]*multag[p]%Mod;
        multag[p]=1;
    }
    if (addtag[p])
    {
        sum[p<<1]=mo(sum[p<<1],addtag[p]*(mid-l+1)%Mod);
        sum[p<<1|1]=mo(sum[p<<1|1],addtag[p]*(r-mid)%Mod);
        addtag[p<<1]=mo(addtag[p<<1],addtag[p]);
        addtag[p<<1|1]=mo(addtag[p<<1|1],addtag[p]);
        addtag[p]=0;
    }
}
void build(int p,int l,int r)
{
    if (l==r)
    {
        sum[p]=a[l];
        multag[p]=1,addtag[p]=0;
        return;
    }
    int mid=(l+r)>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    sum[p]=mo(sum[p<<1],sum[p<<1|1]);
    multag[p]=1;addtag[p]=0;
}
void modify_mul(int p,int l,int r,int i,int j,long long v)
{
    if (l==i && r==j)
    {
        sum[p]=sum[p]*v%Mod;
        multag[p]=multag[p]*v%Mod;
        addtag[p]=addtag[p]*v%Mod;
        return;
    }
    pushdown(p,l,r);
    int mid=(l+r)>>1;
    if (j<=mid) modify_mul(p<<1,l,mid,i,j,v);
    else if (i>mid) modify_mul(p<<1|1,mid+1,r,i,j,v);
    else
    {
        modify_mul(p<<1,l,mid,i,mid,v);
        modify_mul(p<<1|1,mid+1,r,mid+1,j,v);
    }
    sum[p]=mo(sum[p<<1],sum[p<<1|1]);
}
void modify_add(int p,int l,int r,int i,int j,long long v)
{
    if (l==i && r==j)
    {
        sum[p]=mo(sum[p],v*(r-l+1)%Mod);
        addtag[p]=mo(addtag[p],v);
        return;
    }
    pushdown(p,l,r);
    int mid=(l+r)>>1;
    if (j<=mid) modify_add(p<<1,l,mid,i,j,v);
    else if (i>mid) modify_add(p<<1|1,mid+1,r,i,j,v);
    else
    {
        modify_add(p<<1,l,mid,i,mid,v);
        modify_add(p<<1|1,mid+1,r,mid+1,j,v);
    }
    sum[p]=mo(sum[p<<1],sum[p<<1|1]);
}
long long query(int p,int l,int r,int i,int j)
{
    if (l==i && r==j) return sum[p];
    pushdown(p,l,r);
    int mid=(l+r)>>1;
    if (j<=mid) return query(p<<1,l,mid,i,j);
    else if (i>mid) return query(p<<1|1,mid+1,r,i,j);
    else
    {
        return mo(query(p<<1,l,mid,i,mid),query(p<<1|1,mid+1,r,mid+1,j));
    }
}
int main()
{
    n=read(),m=read(),Mod=read();
    for (int i=1;i<=n;i++) a[i]=read(),a[i]%=Mod;
    build(1,1,n);
    while (m--)
    {
        opt=read();
        if (opt==1)
        {
            x=read(),y=read(),k=read();
            k%=Mod;
            modify_mul(1,1,n,x,y,k);
        }
        if (opt==2)
        {
            x=read(),y=read(),k=read();
            k%=Mod;
            modify_add(1,1,n,x,y,k);
        }
        if (opt==3)
        {
            x=read(),y=read();
            printf("%lld\n",query(1,1,n,x,y));
        }
    }
    return 0;
}