題目鏈接
這題寫了我兩個小時,在cf延時的15分鐘內調出來了,直呼內行
D-小C的棋王之路
給個節點用k*x+val 表示lazy更新 初始葉子節點k=1 val=a[l] 其他 k=1 val=0
一個mul數組,記錄每個節點的前面的係數k,val數組記錄後面val的值 sum數組記錄區間和,因爲詢問的是區間和
每次區間乘了一個k:
某個節點記錄:
mul[id]*=k
val[id]*=k
sum[id]*=k
mul[id]=k*mul[id]%mod;
val[id]=k*val[id]%mod;
sum[id]=k*sum[id]%mod;
區間加了一個k:
val[id]+=k
sum[id]+k*(r-l+1) (l,r是某個節點的信息)
add(val[id],k);
add(sum[id],k*(r-l+1)%mod);
區間覆蓋:(驚天妙手,突然想到的處理方式)
mul[id]=0;
val[id]=k;
sum[id]=k*(r-l+1)
mul[id]=0;
val[id]=k;
sum[id]=k*(r-l+1)%mod;
lazy更新:相當於某個節點同時來k倍係數以及加了個 後綴的x值
假設k、x是由id的父親節點傳來,
mul[id]*=k;
val[id]=x+k*val[id]
sum[id]=sum[id]*k+x*(r-l+1)
int root=id,len=r-l+1;
ll p=mod;
mul[id<<1]=mul[id]*mul[id<<1]%mod;
val[id<<1]=(val[id]+val[id<<1]*mul[id]%mod)%mod;
sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p;
mul[id<<1|1]=mul[id]*mul[id<<1|1]%mod;
val[id<<1|1]=(val[id]+val[id<<1|1]*mul[id]%mod)%mod;
sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p;
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
inline ll read()
{
ll x=0,w=1; char c=getchar();
while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
return w==1?x:-x;
}
const int N=2e5+10;
ll n,m,mod;
int mx;
struct node
{
int ty,l,r;
ll k;
}a[N];
ll mul[4*N],val[4*N],sum[4*N],t[N];
int st[4*N];
void add(ll &x,ll y)
{
x=(x+y)%mod;
}
void build(int id,int l,int r)
{
mul[id]=1;
if(l==r){
sum[id]=t[l];
return ;
}
int mid=l+r>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
sum[id]=(sum[id<<1]+sum[id<<1|1])%mod;
}
void pushdown(int id,int l,int r)
{
int mid=l+r>>1;
if(mul[id]==1&&val[id]==0) return;
int root=id,len=r-l+1;
ll p=mod;
mul[id<<1]=mul[id]*mul[id<<1]%mod;
val[id<<1]=(val[id]+val[id<<1]*mul[id]%mod)%mod;
sum[root<<1]=(sum[root<<1]*mul[root]%p+val[root]*(len-(len>>1))%p)%p;
mul[id<<1|1]=mul[id]*mul[id<<1|1]%mod;
val[id<<1|1]=(val[id]+val[id<<1|1]*mul[id]%mod)%mod;
sum[root<<1|1]=(sum[root<<1|1]*mul[root]%p+val[root]*(len>>1)%p)%p;
mul[id]=1,val[id]=0;
}
ll qu(int id,int l,int r,int ql,int qr)
{
if(ql<=l&&r<=qr) return sum[id];
int mid=l+r>>1;
ll ans=0;
pushdown(id,l,r);
if(ql<=mid) ans=qu(id<<1,l,mid,ql,qr);
if(qr>mid) add(ans,qu(id<<1|1,mid+1,r,ql,qr));
//sum[id]=(sum[id<<1|1]+sum[id<<1])%mod;
return ans;
}
void up(int id,int l,int r,int ql,int qr,ll k,int ty)
{
if(ql<=l&&r<=qr){
if(ty==1){
//printf("id:%d sum[id]:%lld\n",id,sum[id]);
add(val[id],k);
add(sum[id],k*(r-l+1)%mod);
//printf("id:%d sum[id]:%lld\n",id,sum[id]);
}
else if(ty==2){
mul[id]=k*mul[id]%mod;
val[id]=k*val[id]%mod;
sum[id]=k*sum[id]%mod;
}
else if(ty==3){
st[id]=-1;
mul[id]=0;
val[id]=k;
sum[id]=k*(r-l+1)%mod;
}
else{
mul[id]=1,val[id]=k;
sum[id]=k*(r-l+1)%mod;
}
return ;
}
pushdown(id,l,r);
int mid=l+r>>1;
if(ql<=mid) up(id<<1,l,mid,ql,qr,k,ty);
if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,k,ty);
sum[id]=(sum[id<<1|1]+sum[id<<1])%mod;
}
int main()
{
n=read(),m=read(),mod=read();
mx=n;
rep(i,1,n) t[i]=read();
for(int i=1;i<=m;++i){
scanf("%d%d",&a[i].ty,&a[i].l);
if(a[i].ty==5) scanf("%d",&a[i].r);
else if(a[i].ty==4) mx++;
else scanf("%d%lld",&a[i].r,&a[i].k),a[i].k%=mod;
a[i].r=min(a[i].r,mx);
a[i].r=min(a[i].r,mx);
}
build(1,1,mx);
int now=n;
for(int i=1;i<=m;++i){
if(a[i].ty==1){
up(1,1,mx,a[i].l,a[i].r,a[i].k,1);
}
else if(a[i].ty==2){
up(1,1,mx,a[i].l,a[i].r,a[i].k,2);
}
else if(a[i].ty==3){
up(1,1,mx,a[i].l,a[i].r,a[i].k,3);
}
else if(a[i].ty==4){
up(1,1,mx,++now,now,a[i].l,4);
}
else if(a[i].ty==5){
printf("%lld\n",qu(1,1,mx,a[i].l,a[i].r));
}
}
}
/*
5 6 9555
1 1 1 1 1
3 2 5 5
5 1 5
1 1 4 5
1 1 5 5
1 3 5 5
5 1 4
5 12 9555
1 1 1 1 1
3 2 5 5
1 1 4 5
1 1 5 5
1 3 5 5
5 1 4
2 1 5 5
2 2 2 5
3 5 5 5
3 3 5 5
5 1 3
1 2 3 5
5 1 3
*/