【分块】bzoj1798 [Ahoi2009]Seq 维护序列seq

分块,打标记,维护两个标记:乘的 和 加的。

每次 区间乘的时候,对 乘标记 和 加标记 都 乘上那个值。

每次 区间加的时候 对 加标记 加上那个值。

(ax+b)*v=axv+bv。开 long long。

  1 #include<cstdio>
  2 #include<cmath>
  3 using namespace std;
  4 typedef long long ll;
  5 int n,sum,sz,num[100001],l[350],r[350],x,y,m,op;
  6 ll MOD,a[100001],sumv[350],lzy1[350],lzy2[350],v;
  7 void makeblock()
  8 {
  9     sz=sqrt(n); if(!sz) sz=1;
 10     for(sum=1;sum*sz<n;sum++)
 11       {
 12           l[sum]=r[sum-1]+1; r[sum]=sum*sz;
 13           for(int i=l[sum];i<=r[sum];++i)
 14           {
 15               num[i]=sum;
 16               sumv[sum]=(sumv[sum]+a[i])%MOD;
 17           }
 18       }
 19     l[sum]=r[sum-1]+1; r[sum]=n;
 20     for(int i=l[sum];i<=r[sum];++i)
 21       {
 22           num[i]=sum;
 23           sumv[sum]=(sumv[sum]+a[i])%MOD;
 24       }
 25     for(int i=1;i<=sum;++i) lzy1[i]=1;
 26 }
 27 void pushdown(const int &p)
 28 {
 29     if(lzy1[p]!=1 || lzy2[p])
 30       {
 31           for(int i=l[p];i<=r[p];++i)
 32           a[i]=(a[i]*lzy1[p]+lzy2[p])%MOD;
 33           lzy1[p]=1; lzy2[p]=0;
 34       }
 35 }
 36 void work1(const int &L,const int &R)
 37 {
 38     sumv[num[L]]=0;
 39     for(int i=L;i<=R;++i) a[i]=(a[i]*v)%MOD;
 40     for(int i=l[num[L]];i<=r[num[L]];++i)
 41       sumv[num[L]]=(sumv[num[L]]+a[i])%MOD;
 42 }
 43 void update1()
 44 {
 45     pushdown(num[x]); pushdown(num[y]);
 46     if(num[x]==num[y]) work1(x,y);
 47     else
 48       {
 49           work1(x,r[num[x]]); work1(l[num[y]],y);
 50           for(int i=num[x]+1;i<num[y];++i)
 51             {
 52                 lzy1[i]=(lzy1[i]*v)%MOD;
 53                 lzy2[i]=(lzy2[i]*v)%MOD;
 54                 sumv[i]=(sumv[i]*v)%MOD;
 55             }
 56       }
 57 }
 58 void work2(const int &L,const int &R)
 59 {
 60     for(int i=L;i<=R;++i) a[i]=(a[i]+v)%MOD;
 61     sumv[num[L]]=(sumv[num[L]]+(ll)(R-L+1)*v)%MOD;
 62 }
 63 void update2()
 64 {
 65     pushdown(num[x]); pushdown(num[y]);
 66     if(num[x]==num[y]) work2(x,y);
 67     else
 68       {
 69           work2(x,r[num[x]]); work2(l[num[y]],y);
 70           for(int i=num[x]+1;i<num[y];++i)
 71           {
 72               lzy2[i]=(lzy2[i]+v)%MOD;
 73               sumv[i]=(sumv[i]+(ll)sz*v)%MOD;
 74           }
 75       }
 76 }
 77 void query()
 78 {
 79     pushdown(num[x]); pushdown(num[y]); ll ans=0;
 80     if(num[x]==num[y]) {for(int i=x;i<=y;++i) ans=(ans+a[i])%MOD;}
 81     else
 82       {
 83           for(int i=x;i<=r[num[x]];++i) ans=(ans+a[i])%MOD;
 84           for(int i=l[num[y]];i<=y;++i) ans=(ans+a[i])%MOD;
 85           for(int i=num[x]+1;i<num[y];++i) ans=(ans+sumv[i])%MOD;
 86       } printf("%d
",(int)ans);
 87 }
 88 int main()
 89 {
 90     scanf("%d%lld",&n,&MOD);
 91     for(int i=1;i<=n;++i) scanf("%lld",&a[i]);
 92     makeblock(); scanf("%d",&m);
 93     for(;m>0;--m)
 94       {
 95           scanf("%d%d%d",&op,&x,&y);
 96           if(op==1) {scanf("%lld",&v); update1();}
 97           else if(op==2) {scanf("%lld",&v); update2();}
 98           else query();
 99       }
100     return 0;
101 }
原文地址:https://www.cnblogs.com/autsky-jadek/p/4123516.html