题意
维护一段序列,支持区间乘,区间加,区间求和。
注意到操作有两种,则维护两个(lazytag),分别对应乘和加。
区间加
与模板1相同。
区间乘
除了更新乘标记,将要加上的部分也要受乘法影响。所以要把两个标记都乘一次。
标记下传
首先乘标记可以直接下传。
而子节点的加标记还没有做乘法,而当前节点已经做了。所以要将子节点乘完在加上当前节点的加标记。
在上述两次标记更新后,分别将子节点的值也更新,就完成了。
代码
#include<iostream>
#define int long long
using namespace std;
const int maxn=100005;
int p,n,m,a[maxn],seg[maxn<<2],tag1[maxn<<2],tag2[maxn<<2];
int u,v,w;
inline void upd(int x)
{
seg[x]=(seg[x<<1]+seg[x<<1|1])%p;
}
inline void build(int x,int l,int r)
{
int mid=(l+r)>>1;
if(l==r)
{
seg[x]=a[l]%p;
return;
}
tag2[x]=1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
upd(x);
}
inline int push_down1(int x,int l,int r)
{
tag1[x<<1]=(tag1[x<<1]*tag2[x]+tag1[x])%p;
tag1[x<<1|1]=(tag1[x<<1|1]*tag2[x]+tag1[x])%p;
int mid=(l+r)>>1;
seg[x<<1]=(seg[x<<1]+(mid-l+1)*tag1[x])%p;
seg[x<<1|1]=(seg[x<<1|1]+(r-mid)*tag1[x])%p;
tag1[x]=0;
tag2[x]=1;
}
inline int push_down2(int x,int l,int r)
{
tag2[x<<1]=(tag2[x<<1]*tag2[x])%p;
tag2[x<<1|1]=(tag2[x<<1|1]*tag2[x])%p;
seg[x<<1]=(seg[x<<1]*tag2[x])%p;
seg[x<<1|1]=(seg[x<<1|1]*tag2[x])%p;
//tag1[x]*=tag2[x];
}
inline int query(int x,int l,int r,int ql,int qr)
{
int temp=0,mid=(l+r)>>1;
if(ql<=l&&r<=qr) return seg[x];
push_down2(x,l,r);
push_down1(x,l,r);
if(ql<=mid) temp=(temp+query(x<<1,l,mid,ql,qr))%p;
if(mid<qr) temp=(temp+query(x<<1|1,mid+1,r,ql,qr))%p;
return temp;
}
inline void modify1(int x,int l,int r,int ql,int qr,int num)
{
if(ql<=l&&r<=qr)
{
seg[x]=(seg[x]+(r-l+1)*num)%p;
tag1[x]=(tag1[x]+num)%p;
} else {
push_down2(x,l,r);
push_down1(x,l,r);
int mid=(l+r)>>1;
if(ql<=mid) modify1(x<<1,l,mid,ql,qr,num);
if(mid<qr) modify1(x<<1|1,mid+1,r,ql,qr,num);
upd(x);
}
}
inline void modify2(int x,int l,int r,int ql,int qr,int num)
{
if(ql<=l&&r<=qr)
{
seg[x]=(seg[x]*num)%p;
tag2[x]=(tag2[x]*num)%p;
tag1[x]=(tag1[x]*num)%p;
} else {
push_down2(x,l,r);
push_down1(x,l,r);
int mid=(l+r)>>1;
if(ql<=mid) modify2(x<<1,l,mid,ql,qr,num);
if(mid<qr) modify2(x<<1|1,mid+1,r,ql,qr,num);
upd(x);
}
}
signed main()
{
ios::sync_with_stdio(false);
cin>>n>>m>>p;
for(int i=1;i<=n;i++)
cin>>a[i];
build(1,1,n);
for(register int i=1;i<=m;i++)
{
cin>>u>>v>>w;
if(u==3)
cout<<query(1,1,n,v,w)<<"
";
else
if(u==1)
{
cin>>u;
modify2(1,1,n,v,w,u);
}else
if(u==2)
{
cin>>u;
modify1(1,1,n,v,w,u);
}
}
return 0;
}