题面
不得不说,这题让我对lazy的理解加深了一步
需要考虑乘与加的优先性
我们设sum是区间和,len为区间长,
x
x
x代表乘上或加上的值
tag1为lazy_add,tag2为lazy_mul
如果我们先加再乘**,即:(sum+tag1
∗
\ast
∗len)
∗
\ast
∗tag2
则乘法操作: (sum+tag1
∗
\ast
∗len)
∗
\ast
∗tag2
∗
\ast
∗x是不会有影响的,所以tar1不变,tar2相乘
但加法操作 (sum+tag1
∗
\ast
∗len)
∗
\ast
∗tag2+x
∗
\ast
∗len
转化后 (sum+len(x
\
\backslash
\tag2+tag1))
∗
\ast
∗tag2。所以这里的tar1+=x
\
\backslash
\tag2,tar1不变
但这样tar1会出现精度问题
所以考虑先乘后加
sum
∗
\ast
∗tag2
+
+
+tag1
∗
\ast
∗len
则乘法操作: (sum
∗
\ast
∗tag2 +tag1
∗
*
∗len)
∗
x
\ast x
∗x
很容易看出我们应该
将 tag1
∗
\ast
∗=
x
x
x,tag2
∗
\ast
∗=
x
x
x
则加法操作: (sum
∗
\ast
∗tag2
+
+
+tag1*len)+x
∗
*
∗len
则只需要将 tar1+=
x
x
x,tar2 不变
代码
#include<bits/stdc++.h>
#define lson rt<<1
#define rson rt<<1|1
using namespace std;
const int maxn=100000+10;
struct tag
{
long long add,mul;
}lazy[maxn<<2];
int n,m;
int p;
long long sum[maxn<<2];
long long res=0;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
inline void pushup(int rt)
{
sum[rt]=sum[lson]+sum[rson];
sum[rt]%=p;
return;
}
inline void pushdown(int rt,int m)
{
sum[lson]=sum[lson]*lazy[rt].mul+lazy[rt].add*(m-(m>>1));
sum[lson]%=p;
sum[rson]=sum[rson]*lazy[rt].mul+lazy[rt].add*(m>>1);
sum[rson]%=p;
lazy[lson].add=lazy[lson].add*lazy[rt].mul+lazy[rt].add;
lazy[lson].add%=p;
lazy[rson].add=lazy[rson].add*lazy[rt].mul+lazy[rt].add;
lazy[rson].add%=p;
lazy[lson].mul*=lazy[rt].mul;
lazy[lson].mul%=p;
lazy[rson].mul*=lazy[rt].mul;
lazy[rson].mul%=p;
lazy[rt].mul=1;
lazy[rt].add=0;
return;
}
inline void build(int l,int r,int rt)
{
lazy[rt].add=0;
lazy[rt].mul=1;
if(l==r)
{
sum[rt]=read();
sum[rt]%=p;
return;
}
int m=(l+r)>>1;
build(l,m,lson);
build(m+1,r,rson);
pushup(rt);
}
inline void update_add(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lazy[rt].add+=c;
lazy[rt].add%=p;
sum[rt]+=c*(r-l+1);
sum[rt]%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update_add(L,R,c,l,m,lson);
if(m<R)
update_add(L,R,c,m+1,r,rson);
pushup(rt);
}
inline void update_mul(int L,int R,int c,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
lazy[rt].mul*=c;
lazy[rt].mul%=p;
lazy[rt].add*=c;
lazy[rt].add%=p;
sum[rt]*=c;
sum[rt]%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
update_mul(L,R,c,l,m,lson);
if(m<R)
update_mul(L,R,c,m+1,r,rson);
pushup(rt);
}
void query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
{
res+=sum[rt];
res%=p;
return;
}
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if(L<=m)
query(L,R,l,m,lson);
if(m<R)
query(L,R,m+1,r,rson);
}
int main()
{
n=read(),m=read(),p=read();
build(1,n,1);
for(int i=1;i<=m;i++)
{
int op=read();
if(op==1)
{
int x=read(),y=read(),k=read();
update_mul(x,y,k,1,n,1);
}
if(op==2)
{
int x=read(),y=read(),k=read();
update_add(x,y,k,1,n,1);
}
if(op==3)
{
int x=read(),y=read();res=0;
query(x,y,1,n,1);
printf("%lld\n",res);
}
}
return 0;
}