RT,已经知道要先乘后加了,所以下传懒标记的时候先下传的乘法标记再下传的加法标记。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int n,m,mod;
ll a[100010],b[400010],lazyflag[400010],lazyflag1[400010];
void build(ll p,ll l,ll r){
if(l==r){
b[p]=a[l];
return;
}
ll m=(l+r)/2;
build(p*2,l,m);
build(p*2+1,m+1,r);
b[p]=b[p*2]+b[p*2+1];
}
void addflag(ll p,ll l,ll r,ll num){
lazyflag[p]+=num%mod;
// b[p]*=lazyflag1[p/2];
b[p]+=(num*(r-l+1))%mod;
}
void addflag1(ll p,ll l,ll r,ll num){
lazyflag1[p]*=num%mod;
b[p]*=num%mod;
}
void revise(ll l1,ll r1,ll l,ll r,ll p,ll num){
if(l1<=l&&r<=r1){
b[p]+=(num*(r-l+1))%mod;
lazyflag[p]+=num;
return;
}
ll m=(l+r)/2;
addflag(p*2,l,m,lazyflag[p]);
addflag(p*2+1,m+1,r,lazyflag[p]);
lazyflag[p]=0;
if(l1<=m){
revise(l1,r1,l,m,p*2,num);
}
if(r1>m){
revise(l1,r1,m+1,r,p*2+1,num);
}
b[p]=(b[p*2]+b[p*2+1])%mod;
}
void revise1(ll l1,ll r1,ll l,ll r,ll p,ll num){
if(l1<=l&&r<=r1){
b[p]*=num%mod;
lazyflag1[p]*=num%mod;
return;
}
ll m=(l+r)/2;
addflag1(p*2,l,m,lazyflag1[p]);
addflag1(p*2+1,m+1,r,lazyflag1[p]);
lazyflag1[p]=1;
if(l1<=m){
revise1(l1,r1,l,m,p*2,num);
}
if(r1>m){
revise1(l1,r1,m+1,r,p*2+1,num);
}
b[p]=(b[p*2]+b[p*2+1])%mod;
}
ll section(ll l1,ll r1,ll l,ll r,ll p){
ll sum=0;
if(l1<=l&&r<=r1){
return b[p]%mod;
}
ll m=(l+r)/2;
addflag1(p*2,l,m,lazyflag1[p]);
addflag1(p*2+1,m+1,r,lazyflag1[p]);
lazyflag1[p]=1;
addflag(p*2,l,m,lazyflag[p]);
addflag(p*2+1,m+1,r,lazyflag[p]);
lazyflag[p]=0;
if(l1<=m){
sum+=section(l1,r1,l,m,p*2);
}
if(r1>m){
sum+=section(l1,r1,m+1,r,p*2+1);
}
return sum%mod;
}
int main(){
cin>>n>>m>>mod;
for(int i=1;i<=400010;i++){
lazyflag1[i]=1;
}
for(int i=1;i<=n;i++){
cin>>a[i];
a[i]%=mod;
}
build(1,1,n);
for(int i=1;i<=m;i++){
int x;
cin>>x;
if(x==1){
int x1,x2,k;
cin>>x1>>x2>>k;
revise1(x1,x2,1,n,1,k);
}
else if(x==2){
int x1,x2,k;
cin>>x1>>x2>>k;
revise(x1,x2,1,n,1,k);
}
else{
int x1,x2;
cin>>x1>>x2;
cout<<section(x1,x2,1,n,1)<<endl;
}
}
return 0;
}
这是代码,求 dalao 指出写挂的地方,本地测了几个小数据都能 A 过