线段树(区间修改)

xiaoxiao2021-02-28  113

题目

区间修改有乘法和加法并存,开两个lazy标记,注意两个lazy标记的下放方式(在注释中)

#include <cstdio> #include <iostream> #define ll long long using namespace std; const int maxn=120000; int p; struct tree{ ll adx,adi;//adx为乘法标记,adi为加法标记 ll l,r; ll sum; }st[maxn<<2];//注意开4倍空间 int a[maxn]; void build(ll o,ll l,ll r) { st[o].l=l,st[o].r=r,st[o].adx=1;//初始化,adi自动赋值为0 if(l==r) { st[o].sum=a[l]; return; } ll mid=(l+r)>>1; build((o<<1),l,mid); build((o<<1)|1,mid+1,r); st[o].sum=(st[(o<<1)].sum+st[(o<<1)|1].sum)%p; } inline void push_down(ll o) { st[(o<<1)].adi=(st[(o<<1)].adi*st[o].adx+st[o].adi)%p;//孩子节点的加法标记一定比爸爸早,所以要×父节点的乘法标记 st[(o<<1)|1].adi=(st[(o<<1)|1].adi*st[o].adx+st[o].adi)%p; st[(o<<1)].adx=(st[(o<<1)].adx*st[o].adx)%p; st[(o<<1)|1].adx=(st[(o<<1)|1].adx*st[o].adx)%p;//同理 st[(o<<1)].sum=((st[o].adi*(st[(o<<1)].r-st[(o<<1)].l+1)%p)%p+(st[(o<<1)].sum*st[o].adx)%p)%p;//计算孩子节点的sum值,adi*len+sum*adx,由于adi已经乘过adx,在此不必再x st[(o<<1)|1].sum=((st[o].adi*(st[(o<<1)|1].r-st[(o<<1)|1].l+1)%p)%p+(st[(o<<1)|1].sum*st[o].adx)%p)%p; st[o].adi=0;st[o].adx=1; } void change_adj(ll o,ll ql,ll qr,ll num) { ll l=st[o].l,r=st[o].r; if(ql==l&&qr==r) { st[o].sum=(st[o].sum+(num*(st[o].r-st[o].l+1)%p)%p)%p; st[o].adi+=num; return; } if(st[o].adi||st[o].adx!=1)//也可以xjb push push_down(o); ll mid=(l+r)>>1; if(qr<=mid) change_adj((o<<1),ql,qr,num); else if(ql>mid) change_adj((o<<1)|1,ql,qr,num); else change_adj((o<<1),ql,mid,num),change_adj((o<<1)|1,mid+1,qr,num); st[o].sum=(st[(o<<1)].sum+st[(o<<1)|1].sum)%p; } void change_adx(ll o,ll ql,ll qr,ll num) { ll l=st[o].l,r=st[o].r; if(ql==l&&qr==r) { st[o].sum=(st[o].sum*num)%p;//在此不要再加adi*len(因为在加值时已经加上了) st[o].adi=(st[o].adi*num)%p; st[o].adx=(st[o].adx*num)%p;//注意三者都要× return; } if(st[o].adi||st[o].adx!=1) push_down(o); ll mid=(l+r)>>1; if(qr<=mid) change_adx((o<<1),ql,qr,num); else if(ql>mid) change_adx((o<<1)|1,ql,qr,num); else change_adx((o<<1),ql,mid,num),change_adx((o<<1)|1,mid+1,qr,num); st[o].sum=(st[(o<<1)].sum+st[(o<<1)|1].sum)%p; } ll ask(ll o,ll ql,ll qr) { ll l=st[o].l,r=st[o].r; if(ql==l&&qr==r) return st[o].sum%p; if(st[o].adi||st[o].adx!=1) push_down(o); ll mid=(l+r)>>1; if(qr<=mid) return ask((o<<1),ql,qr)%p; else if(ql>mid) return ask((o<<1)|1,ql,qr)%p; else return (ask((o<<1),ql,mid)+ask((o<<1)|1,mid+1,qr))%p; } int main() { ll n,m; scanf("%lld%d",&n,&p); for(int i=1;i<=n;i++) scanf("%d",&a[i]); cin>>m; build(1,1,n); for(int i=1;i<=m;i++) { int x; int l,r; ll num; scanf("%d",&x); if(x==1) { scanf("%d%d%lld",&l,&r,&num); change_adx(1,l,r,num); } if(x==2) { scanf("%d%d%lld",&l,&r,&num); change_adj(1,l,r,num); } if(x==3) { scanf("%d%d",&l,&r); printf("%lld\n",ask(1,l,r)%p); } } return 0; }
转载请注明原文地址: https://www.6miu.com/read-44586.html

最新回复(0)