线段树模板 Posted on 2020-01-22 | In 线段树 例题洛谷一道题 线段树的讲解推荐博客 这道题唯一难点在于lazy标记的处理,因为涉及加和乘两种区间修改,需要考虑运算顺序。 板子: 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125#include<bits/stdc++.h>using namespace std;const int maxn=1e5;#define lson (rt<<1)#define rson (rt<<1|1)//lazy_tag定义:记录当前节点的修改量,当前节点此时已完成修改,是这个算法区间修改复杂度优秀的核心//这里add、mul分别是加和乘的lazy标记int p;int a[maxn];struct{ long long val,add,mul;}t[maxn<<2];//由子节点更新父节点的操作,区间合并void pushup(int rt){ t[rt].val=(t[lson].val+t[rson].val)%p;}//lazy标记下移,意味着子节点的值也要修改啦,先更新子节点的值,再补充修改它们的lazy标记//这里我们规定计算顺序:先算乘法再加上add值,add相当于一个附加的offset,所以在更新乘法的lazy时,add标记同时也要乘上这个值。//什么时候需要pushdown?上面提到的博客中很好地总结了:当接下来要用到当前区间的子区间时,需要把父节点之前存留的修改传下去void pushdown(int rt,int l,int r){ int m=(l+r)/2; t[lson].val=(t[lson].val*t[rt].mul%p+(m-l+1)*t[rt].add%p)%p; t[rson].val=(t[rson].val*t[rt].mul%p+(r-m)*t[rt].add%p)%p; t[lson].mul=(t[lson].mul*t[rt].mul)%p; t[rson].mul=(t[rson].mul*t[rt].mul)%p; t[lson].add=(t[lson].add*t[rt].mul%p+t[rt].add)%p; t[rson].add=(t[rson].add*t[rt].mul%p+t[rt].add)%p; t[rt].mul=1; t[rt].add=0; return ;}//bottom-up建树void build(int l,int r,int rt){ t[rt].add=0; t[rt].mul=1; if(l==r){ t[rt].val=a[l-1]; }else{ int m=(l+r)/2; build(l,m,lson); build(m+1,r,rson); pushup(rt); } t[rt].val%=p; return ;}//top-down更新void update_add(int L,int R,int l,int r,int rt,int v){ if(l>=L&&r<=R){ t[rt].add=(t[rt].add+v)%p; t[rt].val=(t[rt].val+(r-l+1)*v%p)%p; return; } pushdown(rt,l,r); int m=(l+r)/2; if(L<=m){ update_add(L,R,l,m,lson,v); } //注意这个地方不能写成if-else,因为这两种情况可能同时出现,不是非此即彼的关系 if(R>m){ update_add(L,R,m+1,r,rson,v); } pushup(rt);}void update_mul(int L,int R,int l,int r,int rt,int v){ if(l>=L&&r<=R){ t[rt].mul=(t[rt].mul*v)%p; t[rt].add=(t[rt].add*v)%p; t[rt].val=(t[rt].val*v)%p; return; } pushdown(rt,l,r); int m=(l+r)/2; if(L<=m){ update_mul(L,R,l,m,lson,v); } if(R>m){ update_mul(L,R,m+1,r,rson,v); } pushup(rt);}long long query(int L,int R,int l,int r,int rt){ if(l>=L&&r<=R){ return t[rt].val; } pushdown(rt,l,r); int m=(l+r)/2; long long res=0LL; if(L<=m){ res+=query(L,R,l,m,lson); } if(R>m){ res+=query(L,R,m+1,r,rson); } return res%p;}int n,m;int main(){ cin>>n>>m>>p; for(int i=0;i<n;i++) scanf("%d",a+i); build(1,n,1); for(int i=0;i<m;i++){ int flag; scanf("%d",&flag); if(flag==1){ int L,R,v; scanf("%d%d%d",&L,&R,&v); update_mul(L,R,1,n,1,v); }else if(flag==2){ int L,R,v; scanf("%d%d%d",&L,&R,&v); update_add(L,R,1,n,1,v); }else{ int L,R; scanf("%d%d",&L,&R); cout<<query(L,R,1,n,1)<<endl; } } return 0;}