数据结构 - 线段树学习笔记
前言
果果终于讲线段树了
线段树太 TM 好用啦!
But,强大的功能是需要码量来实现的。
定义
线段树是一种储存了一个序列的区间信息,并在各个区间中建立了关联的数据结构。
对于任意一个序列都可以建出它的线段树。
它是一颗完全二叉树,它的每一个节点都是一个区间。
对于每一个节点,其左儿子节点为这段区间的左半部分,右儿子节点为这段区间的右半部分。
而且由于是完全二叉树,其根节点的编号为
如下图就是一颗线段树:
根据定义,这样就可以建一颗线段树:
#define ls(x) (x * 2)
#define rs(x) (x * 2 + 1)
struct node {
int l, r, val;
// l : 左端点
// r : 右端点
// val : 区间信息
}tr[N * 4];
void build(int p, int l, int r) {
if(l == r) {tr[p] = node{l, r, \*somevalue*\};return;} // 叶节点特殊处理
int mid = (l + r) >> 1;
build(ls(p), l, mid); // 递归建立左右子区间
build(rs(p), mid + 1, r);
tr[p] = node{l, r, tr[ls(p)].val \*someopt*\ tr[rs(p)].val}; // 这里合并两个子区间的信息
}
由于线段树的树高最多为
Easy-单点修改
实现单点加,区间和
其实这种玩意儿树状数组也可以做,但是线段树也可以实现。
建立一颗线段树,树上维护区间和。
修改
从
void updata(int p, int k, int d) {
if(tr[p].l > k || tr[p].r < k) return; // 不包含
tr[p].val += d;
updata(ls(p), k, d);
updata(rs(p), k, d);
}
查询
从
如果
最后答案为所有被包含区间的区间和之和。
A:Why?
Q:因为如果取了当前讨论区间,那么不会有其他讨论的区间与其相交,因为即没有取其儿子,也没有取其祖先,直接在这里返回了值。
int sum(int p, int l, int r) {
if(tr[p].l > r || tr[p].r < l) return 0;
if(tr[p].l >= l && tr[p].r <= r) return tr[p].val; // 包含
return sum(ls(p), l, r) + sum(rs(p), l , r);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)