数据结构 - 线段树学习笔记

发布时间 2024-01-09 16:56:23作者: 固态H2O

前言

果果终于讲线段树了
线段树太 TM 好用啦!
But,强大的功能是需要码量来实现的。

定义

线段树是一种储存了一个序列的区间信息,并在各个区间中建立了关联的数据结构。
对于任意一个序列都可以建出它的线段树。

它是一颗完全二叉树,它的每一个节点都是一个区间
对于每一个节点,其左儿子节点为这段区间的左半部分,右儿子节点为这段区间的右半部分。
而且由于是完全二叉树,其根节点的编号为 \(1\),对于每一个节点 \(p\),其左儿子节点编号为 \(2p\),右儿子节点编号为 \(2p + 1\)。这种编号方便我们遍历线段树。

如下图就是一颗线段树:

image

根据定义,这样就可以建一颗线段树:

#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}; // 这里合并两个子区间的信息
}

线段树可以在 \(\text{O}(\log n)\) 的时间复杂度中实现单点修改、区间修改、区间查询(区间求和,求区间最大值,求区间最小值)等操作。

Easy-单点修改