线段树入门
线段树的基本操作:
1.单点修改+区间查
#include<bits/stdc++.h> #define lson L,(L+R)/2,p*2 #define rson (L+R)/2+1,R,p*2+1 #define E(i,n) for(int i=1;i<=n;++i) #define F(i,l,r) for(int i=l;i<=r;++i) #define mid (tr[p].l+tr[p].r)/2 #define ll long long using namespace std; const int N=1e5+5; struct node{ int l,r; ll w; }tr[N<<2];//1.开四倍空间 int n,m,a[N]; inline void pushup(int p){ tr[p].w=tr[p*2].w+tr[p*2+1].w; } inline void build(int L,int R,int p){ tr[p]=(node){L,R,a[L]}; if(L==R) return; build(lson); build(rson); pushup(p);//2.记得pushup } inline void upd(int x,int y,int p){ if(tr[p].l==tr[p].r) { tr[p].w+=y; return ; } if(x<=mid) upd(x,y,p*2); else upd(x,y,p*2+1); pushup(p); } inline ll query(int L,int R,int p){ if(tr[p].l>=L && tr[p].r<=R) return tr[p].w; ll res=0; if(L<=mid) res+=query(L,R,p*2); if(R>mid) res+=query(L,R,p*2+1); return res; //3.两个if建议画图分析。等号给一边即可,不然会算重 } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d",&a[i]); build(1,n,1); char op[10]; int x,y; while(m--){ scanf("%s%d%d",op,&x,&y); if(op[0]=='A') upd(x,y,1); if(op[0]=='S') upd(x,-y,1); if(op[0]=='Q') printf("%lld\n",query(x,y,1)); } return 0; }
2.区间修+区间查
inline void pushup(int p){ tr[p].w=tr[ls].w+tr[rs].w; } inline void pushdown(int p){//更新tag if(tr[p].tag){ tr[ls].tag+=tr[p].tag; tr[rs].tag+=tr[p].tag; tr[ls].w+=(tr[ls].r-tr[ls].l+1) * tr[p].tag; tr[rs].w+=(tr[rs].r-tr[rs].l+1) * tr[p].tag; tr[p].tag=0; } } inline void upd(int x,int y,int z,int p){ if(tr[p].l>=x && tr[p].r<=y) { tr[p].w+=(tr[p].r-tr[p].l+1)*z; tr[p].tag+=z; return ; } //w 和 tag都要更新 pushdown(p); if(x<=mid) upd(x,y,z,ls); if(y>mid) upd(x,y,z,rs); //不能写if-else ,因为不是"非左即右" pushup(p); } inline ll query(int x,int y,int p){ if(tr[p].l>=x && tr[p].r<=y) return tr[p].w; pushdown(p); //对比单点修,只多了一步pushdown
ll res=0; if(mid>=x) res+=query(x,y,ls); if(mid<y) res+=query(x,y,rs); // pushup(p); return res; }
3.单点加+区间最值
//变化:pushup 与 qry inline void pushup(int p){ tr[p].w=max(tr[ls].w,tr[rs].w); } inline int qry(int x,int y,int p){ if(x<=tr[p].l && y>=tr[p].r) return tr[p].w; int res=0; if(x<=mid) res=max(res,qry(x,y,ls)); if(y>mid) res=max(res,qry(x,y,rs)); return res; }
4.区间修+单点查
//tr[].w只存变化量 //不用pushup,因为是单点查,所以没有必要维护区间状态,在涉及到的这条链上只需要有这个tag就行
//pushdown的变化也是这个原因:不关心区间状态,只要询问的单点所在的链上有这个tag,用到的时候下传就可以 inline void pushdown(int p){ if(tr[p].w) tr[ls].w+=tr[p].w , tr[rs].w+=tr[p].w , tr[p].w=0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现