BZOJ1798: [Ahoi2009]Seq 维护序列seq

【传送门:BZOJ1798


简要题意:

  给出一个长度为n个序列,有m个操作,共为三种操作:

  1 x y c表示将x到y的值全部*c

  2 x y c表示将x到y的值全部+c

  3 x y求x到y的值的和


题解:

  线段树嘛,区间修改加区间求值

  但是关键是怎么处理乘和加的lazy标记的处理

  首先肯定不能够像之前的题那样直接继承,因为有可能先乘后加再乘,这样子的话,直接继承会错误

  所以我们设lazyc,lazyj表示当前继承时,值为x的数要变成lazyc*x+lazyj

  如果要加c,就变成lazyc*x+lazyj+c

  如果要乘c,就变成lazyc*x^c+lazyj*c就好了


参考代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct node
{
    int l,r,lc,rc;
    LL c,lazyc,lazyj;
}tr[210000];int len;
LL a[110000];
LL Mod;
void update(int now)
{
    int lc=tr[now].lc,rc=tr[now].rc;
    LL j=tr[now].lazyj,c=tr[now].lazyc;
    if(lc!=-1)
    {
        tr[lc].c=(LL(tr[lc].r-tr[lc].l+1)*j%Mod+(c*tr[lc].c)%Mod)%Mod;
        tr[lc].lazyc=(tr[lc].lazyc*c)%Mod;
        tr[lc].lazyj=((tr[lc].lazyj*c)%Mod+j)%Mod;
    }
    if(rc!=-1)
    {
        tr[rc].c=(LL(tr[rc].r-tr[rc].l+1)*j%Mod+(c*tr[rc].c)%Mod)%Mod;
        tr[rc].lazyc=(tr[rc].lazyc*c)%Mod;
        tr[rc].lazyj=((tr[rc].lazyj*c)%Mod+j)%Mod;
    }
    tr[now].lazyc=1;tr[now].lazyj=0;
}
void bt(int l,int r)
{
    len++;int now=len;
    tr[now].l=l;tr[now].r=r;tr[now].c=0;
    tr[now].lc=tr[now].rc=-1;
    tr[now].lazyc=1;tr[now].lazyj=0;
    if(l<r)
    {
        int mid=(l+r)/2;
        tr[now].lc=len+1;bt(l,mid);
        tr[now].rc=len+1;bt(mid+1,r);
    }
}
void cheng(int now,int l,int r,LL c)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].c=(tr[now].c*c)%Mod;
        tr[now].lazyc=(tr[now].lazyc*c)%Mod;
        tr[now].lazyj=(tr[now].lazyj*c)%Mod;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
       if(tr[now].lazyc!=1||tr[now].lazyj!=0) update(now);
    if(r<=mid) cheng(lc,l,r,c);
    else if(l>mid) cheng(rc,l,r,c);
    else cheng(lc,l,mid,c),cheng(rc,mid+1,r,c);
    tr[now].c=(tr[lc].c+tr[rc].c)%Mod;
}
void jia(int now,int l,int r,LL c)
{
    if(tr[now].l==l&&tr[now].r==r)
    {
        tr[now].c=(tr[now].c+LL(r-l+1)%Mod*c)%Mod;
        tr[now].lazyj=(tr[now].lazyj+c)%Mod;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazyc!=1||tr[now].lazyj!=0) update(now);
    if(r<=mid) jia(lc,l,r,c);
    else if(l>mid) jia(rc,l,r,c);
    else jia(lc,l,mid,c),jia(rc,mid+1,r,c);
    tr[now].c=(tr[lc].c+tr[rc].c)%Mod;
}
LL qiuhe(int now,int l,int r)
{
    if(tr[now].l==l&&tr[now].r==r) return tr[now].c;
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(tr[now].lazyc!=1||tr[now].lazyj!=0) update(now);
    if(r<=mid) return qiuhe(lc,l,r);
    else if(l>mid) return qiuhe(rc,l,r);
    else return (qiuhe(lc,l,mid)+qiuhe(rc,mid+1,r))%Mod;
}
int main()
{
    int n;
    scanf("%d%lld",&n,&Mod);
    len=0;bt(1,n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),jia(1,i,i,a[i]);
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        int t;
        scanf("%d",&t);
        if(t==1)
        {
            int x,y;LL c;
            scanf("%d%d%lld",&x,&y,&c);
            cheng(1,x,y,c%Mod);
        }
        if(t==2)
        {
            int x,y;LL c;
            scanf("%d%d%lld",&x,&y,&c);
            jia(1,x,y,c%Mod);
        }
        if(t==3)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%lld\n",qiuhe(1,x,y));
        }
    }
    return 0;
}

 

posted @ 2018-04-09 08:40  Star_Feel  阅读(257)  评论(0编辑  收藏  举报