大佬讲解线段树
https://blog.csdn.net/zearot/article/details/48299459
模板1题目链接
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; ll sum[N<<2]; int lazy[N<<2]; ll a[N]; void Getsum(ll pos){ sum[pos]=sum[pos<<1]+sum[pos<<1|1]; return ; } void PushDown(ll pos,ll lnum,ll rnum){ if(lazy[pos]){ lazy[pos<<1]+=lazy[pos]; lazy[pos<<1|1]+=lazy[pos]; sum[pos<<1]+=lazy[pos]*lnum; sum[pos<<1|1]+=lazy[pos]*rnum; lazy[pos]=0; } return ; } void Update(ll L,ll R,ll C,ll l,ll r,ll pos){ if(l>=L && r<=R){ sum[pos]+=C*(r-l+1); lazy[pos]+=C; return ; } ll m=(l+r)>>1; PushDown(pos,m-l+1,r-m); if(m>=L) Update(L,R,C,l,m,pos<<1); if(m<R) Update(L,R,C,m+1,r,pos<<1|1); Getsum(pos); } void Build(ll l,ll r,ll pos){ if(l==r){ sum[pos]=a[l]; return ; } int m=(l+r)>>1; Build(l,m,pos<<1); Build(m+1,r,pos<<1|1); Getsum(pos); } ll Query(ll L,ll R,ll l,ll r,ll pos){ if(r<=R && l>=L){ return sum[pos]; } int m=(l+r)>>1; PushDown(pos,m-l+1,r-m); ll ans=0; if(m>=L) ans+=Query(L,R,l,m,pos<<1); if(m<R) ans+=Query(L,R,m+1,r,pos<<1|1); return ans; } void solve(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++) cin>>a[i]; Build(1,n,1); for(int i=1;i<=m;i++){ int op; ll x,y,k; cin>>op; if(op==1){ cin>>x>>y>>k; Update(x,y,k,1,n,1); } else{ cin>>x>>y; cout<<Query(x,y,1,n,1)<<endl; } } } int main(){ solve(); }
模板2题目链接
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=2e5+10; int sum[N<<2]; int score[N]; void GetMax(int pos){ sum[pos]=max(sum[pos<<1],sum[pos<<1|1]); } void Build(int l,int r,int pos){ if(l==r){ sum[pos]=score[l]; return ; } int m=(l+r)>>1; Build(l,m,pos<<1); Build(m+1,r,pos<<1|1); GetMax(pos); } void Update(int l,int r,int pos,int id,int grade){ if(l==r){ sum[pos]=grade; return ; } int m=(l+r)>>1; if(id<=m) Update(l,m,pos<<1,id,grade); else Update(m+1,r,pos<<1|1,id,grade); GetMax(pos); } int Query(int L,int R,int l,int r,int pos){ if(l>=L&&r<=R){ return sum[pos]; } int m=(l+r)>>1; int ans=0; if(m>=L) ans=max(ans,Query(L,R,l,m,pos<<1)); if(m<R) ans=max(ans,Query(L,R,m+1,r,pos<<1|1)); return ans; } void solve(){ int n,m; while(~scanf("%d%d",&n,&m)){ for(int i=1;i<=n;i++) scanf("%d",&score[i]); Build(1,n,1); while(m--){ char ch; int l,r; scanf(" %c%d%d",&ch,&l,&r); if(ch=='Q'){ cout<<Query(l,r,1,n,1)<<endl; } else{ Update(1,n,1,l,r); } } } } int main(){ solve(); }
模板3题目链接
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+10; ll add[N<<2],mul[N<<2],ans[N<<2],a[N]; ll mod; void GetAns(int pos){ ans[pos]=(ans[pos<<1]+ans[pos<<1|1])%mod; return ; } void Build(int l,int r,int pos){ mul[pos]=1; add[pos]=0; if(l==r){ ans[pos]=a[l]; return ; } int m=(l+r)>>1; Build(l,m,pos<<1); Build(m+1,r,pos<<1|1); GetAns(pos); } void PushDown(int pos,int ln,int rn){//下传操作,顾名思义,对pos的子节点进行操作,标记的下传和对ans的影响 if(add[pos]!=0 || mul[pos]!=1){ ans[pos<<1]= (ans[pos<<1]*mul[pos]+add[pos]*ln)%mod; ans[pos<<1|1]=(ans[pos<<1|1]*mul[pos]+add[pos]*rn)%mod; add[pos<<1]= (add[pos]+add[pos<<1]*mul[pos])%mod; add[pos<<1|1]=(add[pos]+add[pos<<1|1]*mul[pos])%mod; mul[pos<<1]= (mul[pos<<1]*mul[pos])%mod; mul[pos<<1|1]=(mul[pos<<1|1]*mul[pos])%mod; mul[pos]=1;//清除标记 add[pos]=0;//同上 } } void Mul(int L,int R,int k,int l,int r,int pos){ if(L<=l && r<=R){ ans[pos]=ans[pos]*k%mod; add[pos]=add[pos]*k%mod; mul[pos]=mul[pos]*k%mod; return ; } int m=(l+r)>>1; PushDown(pos,m-l+1,r-m); if(m>=L) Mul(L,R,k,l,m,pos<<1); if(m<R) Mul(L,R,k,m+1,r,pos<<1|1); GetAns(pos);//勿忘 return ; } void Add(int L,int R,int c,int l,int r,int pos){ if(L<=l && r<=R){ ans[pos]=(ans[pos]+c*(r-l+1))%mod;//此位置存在懒标记 add[pos]=(add[pos]+c)%mod; return ; } int m=(l+r)>>1; PushDown(pos,m-l+1,r-m); if(m>=L) Add(L,R,c,l,m,pos<<1); if(m<R) Add(L,R,c,m+1,r,pos<<1|1); GetAns(pos);//勿忘 return ; } ll Query(int L,int R,int l,int r,int pos){ if(L<=l && r<=R){ return ans[pos]; } int m=(l+r)>>1; PushDown(pos,m-l+1,r-m);//勿忘 ll res=0; if(m>=L) res=(res+Query(L,R,l,m,pos<<1))%mod; if(m<R) res=(res+Query(L,R,m+1,r,pos<<1|1))%mod; return res; } void solve(){ int n,m; int op,x,y; ll k,c; cin>>n>>m>>mod; for(int i=1;i<=n;i++) cin>>a[i]; Build(1,n,1); while(m--){ cin>>op; if(op==1){ cin>>x>>y>>k; Mul(x,y,k,1,n,1); } else if(op==2){ cin>>x>>y>>c; Add(x,y,c,1,n,1); } else{ cin>>x>>y; cout<<Query(x,y,1,n,1)<<endl; } } } int main(){ solve(); } //核心是PushDown、Add和Mul,理解了规定乘法的优先级大于加法,就能理解这三个函数的代码了
模板1更新(20201102)
对线段树的理解更深了。
//区间查询 单点修改 #include<bits/stdc++.h> #define ll long long const int N=1e5+100; const int inf=0x3f3f3f3f; using namespace std; struct node{ ll sum,l,r,lazy; }; node tree[N<<2]; int x,y,n,op,m; ll a[N],k; void Build(int i,int l,int r) { tree[i].lazy=0; tree[i].l=l; tree[i].r=r; if(l==r) { tree[i].sum=a[l]; return ; } int mid=(l+r)>>1; Build(i*2,l,mid); Build(i*2+1,mid+1,r); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; return ; } void PushDown(int i) { if(!tree[i].lazy) return ; tree[2*i].sum+=tree[i].lazy*(tree[2*i].r-tree[2*i].l+1); tree[2*i+1].sum+=tree[i].lazy*(tree[2*i+1].r-tree[2*i+1].l+1); tree[2*i].lazy+=tree[i].lazy; tree[2*i+1].lazy+=tree[i].lazy; tree[i].lazy=0; return ; } void Add(int i,int l,int r,ll c) { if(tree[i].l>=l && tree[i].r<=r) { tree[i].lazy+=c; tree[i].sum+=c*(tree[i].r-tree[i].l+1); return ; } PushDown(i); if(tree[2*i].r>=l) Add(2*i,l,r,c); if(tree[2*i+1].l<=r) Add(2*i+1,l,r,c); tree[i].sum=tree[2*i].sum+tree[2*i+1].sum; return ; } ll Query(int i,int l,int r) { ll res=0; if(tree[i].l>=l && tree[i].r<=r) return tree[i].sum; if(tree[i].l>r || tree[i].r<l) return 0; PushDown(i); if(tree[2*i].r>=l) res+=Query(2*i,l,r); if(tree[2*i+1].l<=r) res+=Query(2*i+1,l,r); return res; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); Build(1,1,n); for(int i=1;i<=m;i++) { scanf("%d",&op); if(op==1) { scanf("%d%d%lld",&x,&y,&k); Add(1,x,y,k); } else { scanf("%d%d",&x,&y); printf("%lld\n",Query(1,x,y)); } } }