思路学习于:XTYF_CKY 的博客
看了这个线段树裸题,竟然一时半会写不出,果然线段树水平还是太菜太菜了,学习了上面这位大佬后,让我对lazy更新有了新的认识,之前我自己手写lazy时,也想到了查询的时候也要标记传递,但终归水平太菜,没有完善出来,这个题呢,又有加法又有乘法,但是我可以把乘法和加法处理一下,使得乘法可以优先,比如(2+x)*2我可以转化成2*x+4,这样就可以无所畏惧的同时处理这两个lazy标记而不用担心他们互相影响了。
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
ll sum[maxn*4],add[maxn*4],mul[maxn*4],mod,v;
void pushdown(int o,int ls,int rs,int l,int m,int r)
{
if(l==r||(add[o]==0&&mul[o]==1))return;
add[ls]=(add[ls]*mul[o]+add[o])%mod;
add[rs]=(add[rs]*mul[o]+add[o])%mod;
mul[ls]=mul[ls]*mul[o]%mod;
mul[rs]=mul[rs]*mul[o]%mod;
sum[ls]=(sum[ls]*mul[o]+add[o]*(m-l+1))%mod;
sum[rs]=(sum[rs]*mul[o]+add[o]*(r-m))%mod;
add[o]=0,mul[o]=1;
}
void up(int o,int l,int r,int ql,int qr,int op)
{
int m=(l+r)/2,ls=o*2,rs=o*2+1;
pushdown(o,ls,rs,l,m,r);
if(l>=ql&&r<=qr)
{
if(op==1)
{
mul[o]=v;
sum[o]=sum[o]*v%mod;
}
else
{
add[o]=v;
sum[o]=(sum[o]+v*(r-l+1))%mod;
}
return;
}
if(ql<=m)up(ls,l,m,ql,qr,op);
if(qr>m)up(rs,m+1,r,ql,qr,op);
sum[o]=(sum[ls]+sum[rs])%mod;
}
ll qu(int o,int l,int r,int ql,int qr)
{
int m=(l+r)/2,ls=o*2,rs=o*2+1;
pushdown(o,ls,rs,l,m,r);
if(l>=ql&&r<=qr)return sum[o];
ll res=0;
if(ql<=m)res+=qu(ls,l,m,ql,qr);
if(qr>m)res+=qu(rs,m+1,r,ql,qr);
return res%mod;
}
int main()
{
int n,q,x,y,op;
scanf("%d%d%lld",&n,&q,&mod);
for(int i=1;i<=n*4;i++)mul[i]=1;
for(int i=1;i<=n;i++)
{
scanf("%lld",&v);
up(1,1,n,i,i,2);
}
while(q--)
{
scanf("%d%d%d",&op,&x,&y);
if(op!=3)
{
scanf("%lld",&v);
up(1,1,n,x,y,op);
}
else printf("%lld\n",qu(1,1,n,x,y));
}
}
本文通过解决P3373题目,深入探讨线段树的lazy标记更新策略,特别是如何优雅地处理加法与乘法操作,实现高效的区间更新与查询。作者分享了从XTYF_CKY博客中学习到的技巧,即通过转换乘法和加法运算,确保两者不会互相影响,从而提升线段树的性能。

1104

被折叠的 条评论
为什么被折叠?



