线段树学习笔记
让我们来一步一步理解!
以下是源于oiwiki的一些解释:
线段树通过将每个长度不为1的区间划分至左右两个区间。易得,时间复杂度为O(logn)相比树状数组其可操作性更强。
1.向上更新
void push_up(int rt){//向上更新 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; }
2.向下更新
void push_down(int rt, int m){ if(add[rt]){//若有标记,则将标记向下移动一层 add[rt << 1] += add[rt]; add[rt << 1 | 1] += add[rt]; sum[rt << 1] += (m - (m >> 1)) * add[rt]; sum[rt << 1 | 1] += (m >> 1) * add[rt]; add[rt] = 0;//取消本层标记 } }
3.开始建树
void build(int l, int r, int rt){//建树 add[rt] = 0; if(l == r){ scanf("%lld", &sum[rt]); return; } int mid = (l + r) >> 1; build(lson); build(rson); push_up(rt);//向上更新 }
4.区间更新
void update(int L, int R, ll key, int l, int r, int rt){//区间更新 if(L <= l && R >= r){ //该区间是完整的 sum[rt] += (r - l + 1) * key; add[rt] += key; return; } push_down(rt, r - l + 1);//向下更新,下传标记 int mid = (l + r) >> 1; if(L <= mid) update(L, R, key, lson); if(R > mid) update(L, R, key, rson); push_up(rt);//向上更新 }
5.区间求和
int query(int L, int R, int l, int r, int rt){//区间求和 if(L <= l && R >= r) return sum[rt]; push_down(rt, r - l + 1);//向下更新 int mid = (l + r) >> 1; int ans = 0; if(L <= mid) ans += query(L, R, lson); if(R > mid) ans += query(L, R, rson); return ans; }
例题:poj 3468 3468 -- A Simple Problem with Integers (poj.org)
线段树裸题!
#include<bits/stdc++.h> #define ll long long #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 using namespace std; const int MAXN = 1e5 + 10; ll sum[MAXN << 2]; ll add[MAXN << 2]; void push_up(int rt){//向上更新 sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; } void push_down(int rt, int m){ if(add[rt]){//若有标记,则将标记向下移动一层 add[rt << 1] += add[rt]; add[rt << 1 | 1] += add[rt]; sum[rt << 1] += (m - (m >> 1)) * add[rt]; sum[rt << 1 | 1] += (m >> 1) * add[rt]; add[rt] = 0;//取消本层标记 } } void build(int l, int r, int rt){//建树 add[rt] = 0; if(l == r){ scanf("%lld", &sum[rt]); return; } int mid = (l + r) >> 1; build(lson); build(rson); push_up(rt);//向上更新 } void update(int L, int R, ll key, int l, int r, int rt){//区间更新 if(L <= l && R >= r){ sum[rt] += (r - l + 1) * key; add[rt] += key; return; } push_down(rt, r - l + 1);//向下更新 int mid = (l + r) >> 1; if(L <= mid) update(L, R, key, lson); if(R > mid) update(L, R, key, rson); push_up(rt);//向上更新 } ll query(int L, int R, int l, int r, int rt){//区间求和 if(L <= l && R >= r) return sum[rt];//该区间完整 push_down(rt, r - l + 1);//向下更新 int mid = (l + r) >> 1; ll ans = 0; if(L <= mid) ans += query(L, R, lson); if(R > mid) ans += query(L, R, rson); return ans; } int main(void){ int n, m; scanf("%d%d", &n, &m); build(1, n, 1); while(m--){ char op[3]; int x, y; ll z; scanf("%s", op); if(op[0] == 'C'){ cin>>x>>y>>z; update(x, y, z, 1, n, 1); }else{ cin>>x>>y; printf("%lld\n", query(x, y, 1, n, 1)); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!