线段树有哪些算法?

一 什么是线段树?

线段树是一种二叉树数据结构,用于高效处理区间查询和区间更新问题。它将一个线性区间递归地划分为若干子区间,每个树节点存储相应区间的聚合信息。

1 核心特性

结构:完全二叉树或近似完全二叉树。

存储:每个节点存储一个区间的统计信息。

时间复杂度:

构建:O(n)。

区间查询:O(log n)。

区间更新:O(log n)。

2 基本结构

根节点:[0, n-1]

/ \

0, mid\] \[mid+1, n-1

二 初级线段树算法

1 基础线段树(区间求和)

核心思想:每个节点存储子区间元素的和。

算法步骤:

(1) 构建树:

递归地将区间二分。

叶子节点存储单个元素值。

内部节点存储左右子节点值之和。

(2) 区间查询:

从根节点开始递归。

如果当前区间完全包含在查询区间内,直接返回节点值。

如果与左子区间有重叠,查询左子树。

如果与右子区间有重叠,查询右子树。

合并左右子树结果。

(3)单点更新:

找到对应的叶子节点。

更新叶子节点值?

回溯更新所有祖先节点的和。

2 区间最值查询(RMQ)。

核心思想:每个节点存储子区间的最大值或最小值

算法步骤:

(1)构建过程与求和类似,但节点存储最值而非和。

(2)查询时比较左右子树的最值结果。

(3) 更新时重新计算受影响区间的最值。

三 中级算法

1 懒标记(Lazy Propagation)

核心思想:延迟更新操作,只在需要时执行。

算法步骤:

(1)懒标记设计:

每个节点维护一个懒标记值。

标记表示"该区间需要更新但尚未传递到子节点"。

(2) 区间更新:

更新时如果当前区间完全包含在目标区间内:

更新当前节点值。

设置懒标记(不立即更新子节点)

否则:

先将懒标记下推到子节点。

递归更新左右子树。

更新当前节点值。

(3) 查询时的处理:

遇到有懒标记的节点,先下推标记再查询。

2 区间赋值操作

核心思想:将区间内所有元素设置为指定值

算法步骤:

(1)使用懒标记记录待赋值的值。

(2)下推标记时直接用该值覆盖子节点。

(3)重置子节点的懒标记。

3 区间加值操作

核心思想:给区间内每个元素加上一个固定值

算法步骤:

(1)懒标记记录要加的值。

(2)更新节点值:原值 + 增加值 × 区间长度。

(3)下推时累加子节点的懒标记。

四 高级算法

1 多重懒标记

核心思想:同时支持多种区间操作(如加、乘、赋值)。

算法步骤:

(1)标记优先级:通常赋值 > 乘法 > 加法。

(2)标记处理顺序:

先处理赋值标记。

再处理乘法标记。

最后处理加法标记。

(3) 下推策略:根据标记类型按顺序更新子节点。

2 扫描线算法

核心思想:处理平面矩形面积/周长并集问题。

算法步骤:

(1)事件处理:

将矩形边作为事件(入边/出边)。

按坐标排序处理。

2 线段树维护:

叶子节点表示离散化后的小区间。

节点记录区间被覆盖的次数和覆盖总长度。

动态更新覆盖状态并计算有效长度。

3 主席树(可持久化线段树)

核心思想:保存历史版本,支持查询任意时刻的状态。

算法步骤:

(1)版本管理:

每次更新只创建受影响路径的新副本。

未改变的节点共享引用。

(2) 查询历史:

维护各个版本的根节点。

通过对应版本的根节点访问历史状态。

4 动态开点线段树

核心思想:避免构建完整树结构,按需创建节点。

算法步骤:

(1)初始只有根节点。

(2)在更新过程中动态创建需要的子节点。

(3)适合值域很大但实际数据稀疏的场景。

5 二维线段树

核心思想:扩展到二维平面处理矩形区域查询。

算法步骤:

(1) 树套树结构:

外层线段树管理行区间。

每个外层节点包含一个内层线段树管理列区间。

(2) 操作处理:

在外层树定位行区间。

在内层树处理列区间操作。

时间复杂度:O(log²n)。

五 总结

1 根据问题类型选择

基础统计:区间求和/最值 → 基础线段树。

批量更新:区间修改 → 懒标记线段树。

复杂操作:多种更新类型 → 多重懒标记。

历史查询:版本控制 → 主席树。

稀疏数据:大值域 → 动态开点。

平面问题:二维区域 → 二维线段树/扫描线。

2 性能考虑

(1) 单点操作比区间操作简单。

(2)懒标记增加常数但保持对数复杂度。

(3) 可持久化增加空间复杂度。

(4) 二维线段树时间空间开销都较大。

线段树的核心优势在于其灵活性和效率的平衡,通过不同的节点设计和标记策略,可以适应各种区间处理需求。

相关推荐
兩尛1 小时前
矩阵中非1的数量 (2025B卷
线性代数·算法·矩阵
sheeta19981 小时前
LeetCode 每日一题笔记 日期:2025.11.30 题目:1590.使数组和能被 P 整除
笔记·算法·leetcode
小许学java1 小时前
数据结构-包装类和泛型
数据结构·泛型·包装类·java-se
似水এ᭄往昔1 小时前
【C++】--二叉搜索树
开发语言·数据结构·c++
兩尛1 小时前
HJ43 迷宫问题
算法
小龙报1 小时前
【算法通关指南:数据结构与算法篇(五)】树的 “自我介绍”:从递归定义到存储绝技(vector vs 链式前向星)
c语言·数据结构·c++·算法·链表·启发式算法·visual studio
报错小能手1 小时前
数据结构 顺序栈
数据结构·算法
风筝在晴天搁浅1 小时前
代码随想录 213.打家劫舍Ⅱ
数据结构
点云SLAM1 小时前
C++包装器之类型擦除(Type Erasure)包装器详解(4)
c++·算法·c++17·类型擦除·c++高级应用·c++包装器·函数包装