P3373 【模板】线段树 2 (未完待续)
P3373 【模板】线段树 2
强烈安利这个大佬 超赞!!!
题解
本来以为这个题拿着线段树1的板子改改就好了,但是发现事情并没有那么简单,改了两天。。。
我们看到这个题其实涉及啦乘法和加法两种运算,如何把这两种运算同时塞到懒标记当中呢??似乎有些困难
!!!那么我们可以开两个懒标记啊,一个记录乘法mul[ ],一个记录加法add[ ]
初始化
add[ ] 初始化当然为0,不加减任何数
mul[ ] 初始化当然为1 ,不乘任何数
标记下传以及ADD运算的时候两者都要维护
运算顺序
当我们乘法和加法的懒标记都有的时候
是先加后乘呢?
还是先乘后加呢?
ans:先乘后加
注意
这个题数据算着算着就很大了,一定要都开long long
还有一点就是忽略掉 if (add [ ] ==0)
代码
#include<bits/stdc++.h> using namespace std; #define ll long long //一定要开long long ,不然会炸 const int maxn=1e7+10; ll n,m,x,y,v,opr,mod; ll a[maxn],add[maxn*4],mul[maxn*4]; //add[]加法懒标记,mul[]乘法懒标记 ll sum[maxn*4]; //前缀和 ll ans; void build(ll k,ll l,ll r) //建树 { mul[k]=1; //初始化乘法前缀和为1,表示不变 if(l==r) { sum[k]=a[l]; return ; } ll mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); sum[k]=(sum[k<<1]+sum[k<<1|1])%mod; } void Add(ll k,ll l,ll r,ll mulp,ll sump) //处理懒标记,先乘后加 { sum[k]=(sum[k]*mulp+(r-l+1)*sump)%mod; add[k]=(add[k]*mulp+sump)%mod; mul[k]=(mul[k]*mulp)%mod; } void pushdown(ll k,ll l,ll r,ll mid) //标记下传 { // if(add[k]==0) return ; Add(k<<1,l,mid,mul[k],add[k]); Add(k<<1|1,mid+1,r,mul[k],add[k]); add[k]=0; //清空懒标记 mul[k]=1; } void modifymul(ll k,ll l,ll r,ll x,ll y,ll v) //乘法区间修改 { if(x<=l&&r<=y) return Add(k,l,r,v,0); ll mid=(l+r)>>1; pushdown(k,l,r,mid); if(x<=mid) modifymul(k<<1,l,mid,x,y,v); if(mid<y) modifymul(k<<1|1,mid+1,r,x,y,v); sum[k]=(sum[k<<1]+sum[k<<1|1])%mod; //维护前缀和 } void modifysum(ll k,ll l,ll r,ll x,ll y,ll v) //加法区间修改 { if(x<=l&&r<=y) return Add(k,l,r,1,v); ll mid=(l+r)>>1; pushdown(k,l,r,mid); if(x<=mid) modifysum(k<<1,l,mid,x,y,v); if(mid<y) modifysum(k<<1|1,mid+1,r,x,y,v); sum[k]=(sum[k<<1]+sum[k<<1|1])%mod; } long long query(ll k,ll l,ll r,ll x,ll y) //区间询问 { if(x<=l&&r<=y) return sum[k]; ll mid=(l+r)>>1; ll res=0; pushdown(k,l,r,mid); if(x<=mid) res+=query(k<<1,l,mid,x,y); if(mid<y) res+=query(k<<1|1,mid+1,r,x,y); return res%mod; } int main() { scanf("%ld%ld%ld",&n,&m,&mod); for(ll i=1;i<=n;i++) scanf("%ld",&a[i]); build(1,1,n); for(ll i=1;i<=m;i++) { scanf("%ld%ld%ld",&opr,&x,&y); if(opr==1) { scanf("%ld",&v); modifymul(1,1,n,x,y,v); } if(opr==2) { scanf("%ld",&v); modifysum(1,1,n,x,y,v); } if(opr==3) { ans=query(1,1,n,x,y); printf("%ld\n",ans%mod); } } return 0; }