P3373 【模板】线段树 2
题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
线段树维护区间乘法
1.如何修改?
一个数去乘区间里的每一个数,那么这个区间的和会乘以这个数,需要乘法标记,初始化为1,乘法标记要乘以这个数,来下传到他的子树中,即更新他的子区间,当然,他的加法标记也要乘以这个数。
2.如何更新?
他子树的值=它的乘法标记*它子树的值+他子树的区间长度*它的加法标记
乘法标记更新,加法标记更新
某位大佬的线段树
#include<bits/stdc++.h> #define N 4000000 #define LL long long #define RE register #define IN inline using namespace std; IN void in(LL &x){ RE char c=getchar();x=0;int f=1; while(!isdigit(c)) {if(c=='-') f=-1;c=getchar();} while(isdigit(c)){x=x*10+c-'0';c=getchar();} x*=f; } /* 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 */ LL n,m,X,ans,p; struct node{ LL l,r,w,f,mul; }e[N]; IN void build(LL k,LL l,LL r){ e[k].l=l;e[k].r=r;e[k].mul=1;e[k].f=0; if(l==r){ in(e[k].w);return; }LL mid=(l+r)/2; build(k*2,l,mid);build(k*2+1,mid+1,r); e[k].w=(e[k*2].w+e[k*2+1].w)%p; } IN void down(LL k){ LL mu=e[k].mul,ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2; e[k*2].w=(e[k*2].w*mu+e[k].f*(mid-ll+1))%p; e[k*2+1].w=(e[k*2+1].w*mu+e[k].f*(rr-mid))%p; e[k*2].mul=(e[k*2].mul*mu)%p; e[k*2+1].mul=(e[k*2+1].mul*mu)%p; e[k*2].f=(e[k*2].f*mu+e[k].f)%p; e[k*2+1].f=(e[k*2+1].f*mu+e[k].f)%p; e[k].f=0;e[k].mul=1; } IN void mull(LL k,LL l,LL r){ LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2; if(ll>=l&&rr<=r){ e[k].w=(e[k].w*X)%p; e[k].mul=(e[k].mul*X)%p; e[k].f=(e[k].f*X)%p; return ; }if(e[k].f!=0||e[k].mul!=1) down(k); if(l<=mid) mull(k*2,l,r);if(r>mid) mull(k*2+1,l,r); e[k].w=(e[k*2].w+e[k*2+1].w)%p; } IN void change_LLerval(LL k,LL l,LL r){ LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2; if(ll>=l&&rr<=r){ e[k].f=(e[k].f+X)%p; e[k].w=((rr-ll+1)*X+e[k].w)%p;return ; }if(e[k].f!=0||e[k].mul!=1) down(k); if(l<=mid) change_LLerval(k*2,l,r);if(r>mid) change_LLerval(k*2+1,l,r); e[k].w=(e[k*2].w+e[k*2+1].w)%p; } IN void ask_LLerval(LL k,LL l,LL r){ LL ll=e[k].l,rr=e[k].r,mid=(ll+rr)/2; if(ll>=l&&rr<=r){ ans=(e[k].w+ans)%p;return; }if(e[k].f!=0||e[k].mul!=1) down(k); if(l<=mid) ask_LLerval(k*2,l,r);if(r>mid) ask_LLerval(k*2+1,l,r); e[k].w=(e[k*2].w+e[k*2+1].w)%p; } int main() { in(n);in(m);in(p); build(1,1,n); while(m--){ LL tp,x,y,k; in(tp);in(x);in(y); if(tp!=3) in(k); if(tp==1) X=k,mull(1,x,y); else if(tp==2) X=k,change_LLerval(1,x,y); else{ ans=0,ask_LLerval(1,x,y); printf("%d ",ans); } }return 0; }
B数据结构
链接:https://www.nowcoder.com/acm/contest/200/B
来源:牛客网
qn姐姐最好了~
qn姐姐给你了一个长度为n的序列还有m次操作让你玩,
1 l r 询问区间[l,r]内的元素和
2 l r 询问区间[l,r]内的元素的平方 和
3 l r x 将区间[l,r]内的每一个元素都乘上x
4 l r x 将区间[l,r]内的每一个元素都加上x
维护区间平方和的值。其他类似吧。。
#include<bits/stdc++.h> #define N int(1e6) #define LL long long using namespace std; void in(LL &x) { register char c=getchar(); x=0; int f=1; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f; } struct node{ LL l,r,w1,w2,mul,ad; }tr[N]; inline void push_up(int k){ tr[k].w1=tr[k<<1].w1+tr[k<<1|1].w1; tr[k].w2=tr[k<<1].w2+tr[k<<1|1].w2; } inline void build(LL k,LL l,LL r){ tr[k].l=l,tr[k].r=r,tr[k].mul=1; if(l==r) { in(tr[k].w1); tr[k].w2=tr[k].w1*tr[k].w1; return; } LL mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); push_up(k); } inline void push_down(LL k){ tr[k<<1].w2=tr[k<<1].w2*tr[k].mul*tr[k].mul+tr[k<<1].w1*2*tr[k].ad+(tr[k<<1].r-tr[k<<1].l+1)*tr[k].ad*tr[k].ad; tr[k<<1].w1=tr[k<<1].w1*tr[k].mul+tr[k].ad*(tr[k<<1].r-tr[k<<1].l+1); tr[k<<1].ad+=tr[k].ad; tr[k<<1].mul*=tr[k].mul; tr[k<<1|1].w2=tr[k<<1|1].w2*tr[k].mul*tr[k].mul+tr[k<<1|1].w1*2*tr[k].ad+(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].ad*tr[k].ad; tr[k<<1|1].w1=tr[k<<1|1].w1*tr[k].mul+tr[k].ad*(tr[k<<1|1].r-tr[k<<1|1].l+1); tr[k<<1|1].ad+=tr[k].ad; tr[k<<1|1].mul*=tr[k].mul; tr[k].ad=0,tr[k].mul=1; } inline void update_mul(LL k,LL L,LL R,LL w){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R){ tr[k].mul*=w; tr[k].ad*=w; tr[k].w2=w*w*tr[k].w2; tr[k].w1=w*tr[k].w1; return; } push_down(k); if(L<=mid) update_mul(k<<1,L,R,w); if(R>mid) update_mul(k<<1|1,L,R,w); push_up(k); } inline void update(LL k,LL L,LL R,LL w){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R){ tr[k].w2+=tr[k].w1*2*w+(r-l+1)*w*w; tr[k].w1+=w*(r-l+1); tr[k].ad+=w; return; } push_down(k); if(L<=mid) update(k<<1,L,R,w); if(R>mid) update(k<<1|1,L,R,w); push_up(k); } LL query1(LL k,LL L,LL R){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R) return tr[k].w1; push_down(k); LL an=0; if(L<=mid) an+=query1(k<<1,L,R); if(R>mid) an+=query1(k<<1|1,L,R); push_up(k); return an; } LL query2(LL k,LL L,LL R){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R) return tr[k].w2; push_down(k); LL an=0; if(L<=mid) an+=query2(k<<1,L,R); if(R>mid) an+=query2(k<<1|1,L,R); push_up(k); return an; } LL n,m; int main() { in(n),in(m); build(1,1,n); for(LL opt,l,r,w,i=1;i<=m;i++){ in(opt),in(l),in(r); if(opt==1){ printf("%lld ",query1(1,l,r)); } if(opt==2){ printf("%lld ",query2(1,l,r)); } if(opt==3){ in(w); update_mul(1,l,r,w); } if(opt==4){ in(w); update(1,l,r,w); } } return 0; }