分块,打标记,维护两个标记:乘的 和 加的。
每次 区间乘的时候,对 乘标记 和 加标记 都 乘上那个值。
每次 区间加的时候 对 加标记 加上那个值。
(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\n",(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 }
时间: 2024-09-30 18:38:43