BZOJ 1798 [Ahoi2009]Seq 维护序列seq

2017.09.12

题目大意

维护一个序列,支持:区间每个数加上某个数,乘以某个数,查询某区间的和。


双标记线段树板子题。直接维护就可以了。

注意对称的东西在复制粘贴的时候不!能!写!错!

#include <cstdio>
#include <algorithm>
using namespace std;
#define lson pos<<1
#define rson pos<<1|1
#define maxN 100010
int inx,iny,inz,mode,mo,n,m,a[maxN];
long long val[maxN<<2],lazup[maxN<<2],lazmul[maxN<<2];
void pushup(int pos) {val[pos]=(val[lson]+val[rson])%mo;}
void pushdown(int pos,int l,int r)
{
    int mid=(l+r)>>1;
    if(lazmul[pos]!=1)
    {
        lazup[lson]=(lazup[lson]*lazmul[pos])%mo;
        lazup[rson]=(lazup[rson]*lazmul[pos])%mo;
        val[lson]=(val[lson]*lazmul[pos])%mo,val[rson]=(val[rson]*lazmul[pos])%mo;
        lazmul[lson]=(lazmul[lson]*lazmul[pos])%mo,lazmul[rson]=(lazmul[rson]*lazmul[pos])%mo;
        lazmul[pos]=1;
    }
    if(lazup[pos])
    {
        val[lson]=(val[lson]+lazup[pos]*(mid-l+1))%mo,val[rson]=(val[rson]+lazup[pos]*(r-mid))%mo;
        lazup[lson]=(lazup[lson]+lazup[pos])%mo,lazup[rson]=(lazup[rson]+lazup[pos])%mo;
        lazup[pos]=0;
    }
}
void mul(int pos,int l,int r,int x,int y,int z)
{
    if(x<=l&&r<=y)
    {
        lazup[pos]=(lazup[pos]*z)%mo,lazmul[pos]=(lazmul[pos]*z)%mo,val[pos]=(val[pos]*z)%mo;
        return;
    }
    pushdown(pos,l,r);
    int mid=(l+r)>>1;
    if(x<=mid) mul(lson,l,mid,x,y,z);
    if(y>mid) mul(rson,mid+1,r,x,y,z);
    pushup(pos);
}
void add(int pos,int l,int r,int x,int y,int z)
{
    if(x<=l&&r<=y)
    {
        lazup[pos]=(lazup[pos]+z)%mo,val[pos]=(val[pos]+1ll*z*(r-l+1))%mo;
        return;
    }
    pushdown(pos,l,r);
    int mid=(l+r)>>1;
    if(x<=mid) add(lson,l,mid,x,y,z);
    if(y>mid) add(rson,mid+1,r,x,y,z);
    pushup(pos);
}
void build(int pos,int l,int r)
{
    lazmul[pos]=1;
    if(l==r)
    {
        val[pos]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(pos);
}
long long query(int pos,int l,int r,int x,int y)
{
    if(x<=l&&r<=y) return val[pos];
    pushdown(pos,l,r);
    int mid=(l+r)>>1;
    long long ret=0;
    if(x<=mid) ret=(ret+query(lson,l,mid,x,y))%mo;
    if(y>mid) ret=(ret+query(rson,mid+1,r,x,y))%mo;
    return ret;
}
int main()
{
    scanf("%d%d",&n,&mo);
    for(int i=1;i<=n;++i)scanf("%d",a+i);
    build(1,1,n);
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&mode);
        switch(mode)
        {
            case 1:{scanf("%d%d%d",&inx,&iny,&inz),mul(1,1,n,inx,iny,inz);break;}
            case 2:{scanf("%d%d%d",&inx,&iny,&inz),add(1,1,n,inx,iny,inz);break;}
            case 3:{scanf("%d%d",&inx,&iny),printf("%lld\n",query(1,1,n,inx,iny)%mo);break;}
        }
    }
    return 0;
}