洛谷 P2023 [AHOI2009]维护序列 || 线段树加法和乘法运算

原理倒是非常简单。设原数为x,加法的lazytag为b,乘法的lazytag为a,操作数为c,那么原式为ax+b,乘上c后(ax+b)c=(ac)*x+b*c,加上c后(ax+b)+c=ax+(b+c),因此加法时只需要更新加法的lazytag,乘法的时候就需要同时乘乘法和加法的lazytag。(乘法时的操作曾经搞错)

有些细节却很难受啊...比如很容易忘记加取模(一般都是程序打完了之后再补上,但是这个程序要补的地方太多,容易漏,要小心),把乘法的lazytag初始化为1出错,很容易少几句话...

  1 //以下代码中:加important标记的是曾经缺少的,注释掉的是曾经多的
  2 #include<cstdio>
  3 #include<cstring>
  4 #define lc (num<<1)
  5 #define rc (num<<1|1)
  6 #define mid ((l+r)>>1)
  7 typedef long long LL;
  8 LL a[300100];
  9 LL tree[1200100],laz[1200100],laz2[1200100];
 10 LL L,R,x,n,m,md;
 11 void build(LL l,LL r,LL num)
 12 {
 13     laz2[num]=1;//important
 14     if(l==r)
 15     {
 16         tree[num]=a[l]%md;
 17         return;
 18     }
 19     build(l,mid,lc);
 20     build(mid+1,r,rc);
 21     tree[num]=(tree[lc]+tree[rc])%md;
 22 }
 23 void pushdown(LL l,LL r,LL num)
 24 {
 25     if(laz2[num]!=1)
 26     {
 27         laz2[lc]=(laz2[lc]*laz2[num])%md;
 28         laz2[rc]=(laz2[rc]*laz2[num])%md;
 29         /*important*/
 30         laz[lc]=(laz[lc]*laz2[num])%md;
 31         laz[rc]=(laz[rc]*laz2[num])%md;
 32         tree[lc]=(tree[lc]*laz2[num])%md;
 33         tree[rc]=(tree[rc]*laz2[num])%md;
 34         /*-important*/
 35         /*
 36         tree[lc]=(tree[lc]+(mid-l+1)*laz2[num])%md;
 37         tree[rc]=(tree[rc]+(r-mid)*laz2[num])%md;
 38         */
 39         laz2[num]=1;
 40     }
 41     if(laz[num])
 42     {
 43         laz[lc]=(laz[lc]+laz[num])%md;
 44         laz[rc]=(laz[rc]+laz[num])%md;
 45         tree[lc]=(tree[lc]+(mid-l+1)*laz[num]%md)%md;
 46         tree[rc]=(tree[rc]+(r-mid)*laz[num]%md)%md;
 47         laz[num]=0;
 48     }
 49 }
 50 void update(LL l,LL r,LL num)
 51 {
 52     if(L<=l&&r<=R)
 53     {
 54         tree[num]=(tree[num]+(r-l+1)*x)%md;
 55         laz[num]=(laz[num]+x)%md;
 56         return;
 57     }
 58     pushdown(l,r,num);
 59     if(L<=mid)    update(l,mid,lc);
 60     if(mid<R)    update(mid+1,r,rc);//if(mid+1<=R)//等价
 61     /*important*/tree[num]=(tree[lc]+tree[rc])%md;
 62 }
 63 void update2(LL l,LL r,LL num)
 64 {
 65     if(L<=l&&r<=R)
 66     {
 67         tree[num]=(tree[num]*x)%md;
 68         /*importaant*/laz[num]=(laz[num]*x)%md;/*important*/
 69         laz2[num]=(laz2[num]*x)%md;
 70         return;
 71     }
 72     pushdown(l,r,num);
 73     if(L<=mid)    update2(l,mid,lc);
 74     if(mid<R)    update2(mid+1,r,rc);//if(mid+1<=R)//等价
 75     /*important*/tree[num]=(tree[lc]+tree[rc])%md;
 76 }
 77 LL query(LL l,LL r,LL num)
 78 {
 79     if(L<=l&&r<=R)    return tree[num];
 80     pushdown(l,r,num);
 81     LL ans=0;
 82     if(L<=mid)    ans=(ans+query(l,mid,lc))%md;
 83     if(mid<R)    ans=(ans+query(mid+1,r,rc))%md;
 84     return ans;
 85 }
 86 int main()
 87 {
 88     LL i,t;
 89     scanf("%lld%lld%lld",&n,&m,&md);
 90     for(i=1;i<=n;i++)
 91         scanf("%lld",&a[i]);//不应该将laz2[]=1写在此处important
 92     build(1,n,1);
 93     for(i=1;i<=m;i++)
 94     {
 95         scanf("%lld",&t);
 96         if(t==2)
 97         {
 98             scanf("%lld%lld%lld",&L,&R,&x);
 99             update(1,n,1);
100         }
101         else if(t==3)
102         {
103             scanf("%lld%lld",&L,&R);
104             printf("%lld\n",query(1,n,1)%md);
105         }
106         else
107         {
108             scanf("%lld%lld%lld",&L,&R,&x);
109             update2(1,n,1);
110         }
111     }
112     return 0;
113 }
posted @ 2017-10-18 19:48  hehe_54321  阅读(506)  评论(0编辑  收藏  举报
AmazingCounters.com