线段树(Segment Tree)原理与实现
字数 878 2025-11-07 12:33:56
线段树(Segment Tree)原理与实现
线段树是一种用于处理区间查询和区间更新问题的高效数据结构,特别适合解决范围最小值、最大值、求和等问题。
一、问题背景与基本概念
假设需要处理一个数组的区间操作,例如:
- 查询区间[L,R]的最小值
- 更新某个位置的值
传统暴力方法查询时间复杂度O(n),更新O(1)。线段树通过预处理将查询和更新都优化到O(log n)。
线段树的核心思想是将区间递归二分,每个节点代表一个区间:
- 叶子节点:代表单个元素区间
- 非叶子节点:代表左右子节点区间的合并
二、线段树的构建过程
以数组[2, 4, 1, 7, 5]为例,构建求和线段树:
-
递归划分区间
-
自底向上计算节点值
[0,4]:19 ← [0,2]:7 + [3,4]:12 [0,2]:7 ← [0,1]:6 + [2,2]:1 [0,1]:6 ← [0,0]:2 + [1,1]:4
三、区间查询操作
查询[1,3]区间和:
- 从根节点0,4开始,目标区间覆盖左右子节点
- 左子树0,2:目标区间[1,3]部分覆盖该节点
- 继续查询左子树的右边界[2,2](完全在目标区间内)
- 右子树[3,4]:目标区间部分覆盖
- 继续查询右子树的左边界[3,3](在目标区间内)
- 合并结果:arr[1]+arr[2]+arr[3] = 4+1+7=12
四、单点更新操作
更新位置2的值为6:
- 从根节点向下递归找到对应叶子节点[2,2]
- 更新叶子节点值:1→6
- 回溯更新所有祖先节点:
五、区间更新优化(懒惰传播)
当需要更新整个区间时,引入懒惰标记:
- 更新区间时,先标记需要更新的值,不立即更新所有子节点
- 查询时再根据标记实际更新
例如给区间0,2加3:
- 在节点0,2标记"待加3"
- 实际更新延迟到查询时执行
六、代码实现要点
class SegmentTree:
def __init__(self, data):
self.n = len(data)
self.size = 1
while self.size < self.n: # 计算最接近的2的幂次
self.size *= 2
self.tree = [0] * (2 * self.size)
# 初始化叶子节点
for i in range(self.n):
self.tree[self.size + i] = data[i]
# 自底向上构建
for i in range(self.size-1, 0, -1):
self.tree[i] = self.tree[2*i] + self.tree[2*i+1]
七、应用场景
- 区间最值查询(RMQ问题)
- 区间求和、求积
- 区间更新(增加、赋值)
- 二维线段树处理矩阵操作
线段树通过O(n)预处理时间,实现O(log n)的查询和更新,是处理区间问题的标准解决方案。