这题有毒啊,敲了我一晚上加一早上,总算A了。
由于有加和乘两个操作,要用2个lazy数组。
核心难点就是2个lazy数组会相互影响。
因为乘影响加,加不影响乘,所以我们先算乘。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <list>
#define rep(i,m,n) for(int i=m;i<=n;i++)
#define dop(i,m,n) for(int i=m;i>=n;i--)
#define lowbit(x) (x&(-x))
#define ll long long
#define INF 2147483647
using namespace std;
inline int read(){ //不写快读据说可能TLE
int s=0,w=1;
char ch=getchar();
while(ch<='0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
const int maxn=100000;
ll a[maxn+10],sum[(maxn<<2)+10],n,m,b,c,d,e,add[(maxn<<2)+10],mul[(maxn<<2)+10],mod; //安全起见,都开long long
void PushDown(int now,int m){ //now:线段编号,m:线段长度
if(mul[now]!=1){ //乘法lazy数组都赋值为1
mul[now<<1]*=mul[now];
mul[now<<1|1]*=mul[now];
sum[now<<1]*=mul[now];
sum[now<<1|1]*=mul[now];
add[now<<1]*=mul[now];
add[now<<1|1]*=mul[now];
mul[now<<1]%=mod;
mul[now<<1|1]%=mod;
sum[now<<1]%=mod;
sum[now<<1|1]%=mod;
add[now<<1]%=mod;
add[now<<1|1]%=mod;
mul[now]=1;
}
if(add[now]){
add[now<<1]+=add[now];
add[now<<1|1]+=add[now];
sum[now<<1]+=add[now]*(m-(m>>1));
sum[now<<1|1]+=add[now]*(m>>1);
add[now<<1]%=mod; //多mod几下,不会错
add[now<<1|1]%=mod;
sum[now<<1]%=mod;
sum[now<<1|1]%=mod;
add[now]=0;
}
}
void Build(int now,int l,int r){ //建树
mul[now]=1;
if(l==r) sum[now]=a[l];
else{
int mid=(l+r)>>1;
Build(now<<1,l,mid);
Build(now<<1|1,mid+1,r);
sum[now]=sum[now<<1]+sum[now<<1|1];
}
}
ll Query(int now,int l,int r,int wl,int wr){ //查询
if(l>wr||r<wl) return 0;
if(l>=wl&&r<=wr) return sum[now];
PushDown(now,r-l+1);
int mid=(l+r)>>1;
return (Query(now<<1,l,mid,wl,wr)%mod+Query(now<<1|1,mid+1,r,wl,wr)%mod)%mod;
}
void Change(int now,int l,int r,int wl,int wr,int p,int mode){ //改值,mode=1:加法,mode=2:乘法
if(l>wr||r<wl) return; //如果当前区间不在需要改值的区间内,返回
if(l>=wl&&r<=wr){ //如果当前区间包括在需要改值的区间内,改这段的值,并标记lazy
if(mode) add[now]+=p,sum[now]+=p*(r-l+1),add[now]%=mod,sum[now]%=mod;
else mul[now]*=p,sum[now]*=p,add[now]*=p,add[now]%=mod,sum[now]%=mod,mul[now]%=mod; //如果是乘法,要把加法lazy的值也改掉(乘法分配率)
return;
}
PushDown(now,r-l+1);
int mid=(l+r)>>1;
Change(now<<1,l,mid,wl,wr,p,mode);
Change(now<<1|1,mid+1,r,wl,wr,p,mode);
sum[now]=(sum[now<<1]+sum[now<<1|1])%mod;
}
int main(){
n=read();m=read();mod=read();
rep(i,1,n) a[i]=read();
Build(1,1,n);
rep(i,1,m){
b=read();
if(b==1){
c=read();d=read();e=read();
Change(1,1,n,c,d,e,0);
}
if(b==2){
c=read();d=read();e=read();
Change(1,1,n,c,d,e,1);
}
if(b==3){
c=read();d=read();
printf("%lld\n",Query(1,1,n,c,d));
}
}
return 0;
}