【模板】线段树3

tech2023-12-24  74

前往:我自己搭建的博客

题目

洛谷P3373线段树2

题解

此题关键在于处理两种延迟标记的关系。假设一个数x受到了+a操作后,又受到了*b操作,则(x+a)*b=x*b+a*b,相当于对x先*b,再+a*b。假设一个数x受到了*a操作后,又受到了+b操作,则x*a+b。这样就可以确定+标记和*标记的相对简单的操作顺序,即先处理乘法,后处理加法。

代码

#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1e5+5; int n,m; ll MOD; ll a[maxn]; struct Segment_tree{ll l,r,sum,tag_add,tag_mul;}t[maxn<<2]; void build(int p,int l,int r) { t[p].l=l,t[p].r=r,t[p].tag_mul=1; //注意初始化乘法标记 if(l==r) {t[p].sum=a[l]; return;} int mid=(l+r)>>1; build(p<<1,l,mid),build(p<<1|1,mid+1,r); t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%MOD; } inline void spread(int p) { if(t[p].tag_mul!=1) { t[p<<1].sum=t[p<<1].sum*t[p].tag_mul%MOD; t[p<<1|1].sum=t[p<<1|1].sum*t[p].tag_mul%MOD; t[p<<1].tag_add=(t[p<<1].tag_add*t[p].tag_mul)%MOD; t[p<<1|1].tag_add=(t[p<<1|1].tag_add*t[p].tag_mul)%MOD; t[p<<1].tag_mul=t[p<<1].tag_mul*t[p].tag_mul%MOD; t[p<<1|1].tag_mul=t[p<<1|1].tag_mul*t[p].tag_mul%MOD; t[p].tag_mul=1; } if(t[p].tag_add!=0) { t[p<<1].sum=(t[p<<1].sum+t[p].tag_add*(t[p<<1].r-t[p<<1].l+1)%MOD)%MOD; t[p<<1|1].sum=(t[p<<1|1].sum+t[p].tag_add*(t[p<<1|1].r-t[p<<1|1].l+1)%MOD)%MOD; t[p<<1].tag_add=(t[p<<1].tag_add+t[p].tag_add)%MOD; t[p<<1|1].tag_add=(t[p<<1|1].tag_add+t[p].tag_add)%MOD; t[p].tag_add=0; } } void add(int p,int l,int r,ll k) { if(l<=t[p].l&&r>=t[p].r) { t[p].sum=(t[p].sum+k*(t[p].r-t[p].l+1)%MOD)%MOD; t[p].tag_add=(t[p].tag_add+k)%MOD; return; } spread(p); int mid=(t[p].l+t[p].r)>>1; if(l<=mid) add(p<<1,l,r,k); if(r>mid) add(p<<1|1,l,r,k); t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%MOD; } void mul(int p,int l,int r,ll k) { if(l<=t[p].l&&r>=t[p].r) { t[p].sum=t[p].sum*k%MOD; t[p].tag_add=t[p].tag_add*k%MOD; t[p].tag_mul=t[p].tag_mul*k%MOD; return; } spread(p); int mid=(t[p].l+t[p].r)>>1; if(l<=mid) mul(p<<1,l,r,k); if(r>mid) mul(p<<1|1,l,r,k); t[p].sum=(t[p<<1].sum+t[p<<1|1].sum)%MOD; } ll ask(int p,int l,int r) { if(l<=t[p].l&&r>=t[p].r) return t[p].sum; spread(p); int ans=0,mid=(t[p].l+t[p].r)>>1; if(l<=mid) ans=(ans+ask(p<<1,l,r))%MOD; if(r>mid) ans=(ans+ask(p<<1|1,l,r))%MOD; return ans; } int main() { scanf("%d%d%lld",&n,&m,&MOD); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); build(1,1,n); for(int i=1;i<=m;i++) { int t,x,y; ll k; scanf("%d%d%d",&t,&x,&y); if(t==1) {scanf("%lld",&k); mul(1,x,y,k);} else if(t==2) {scanf("%lld",&k); add(1,x,y,k);} else printf("%lld\n",ask(1,x,y)); } return 0; }

 

最新回复(0)