【模板】线段树
线段树
线段树是 OI 竞赛中最强大的数据结构之一,可以用来维护和、积以及最值等具有合并性质的信息。
一般线段树
P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P3373 【模板】线段树 2 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
以模板一为例:
1 | struct SegmentTree |
动态开点线段树
在遇到需要以权值为下标建立的线段树时,有时候过大的值域使得无法如上种方式建立线段树,这时候需要权值线段树和动态开点的技巧。
T125847 【模板】动态开点线段树 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P3372 【模板】线段树 1 - 洛谷 | 计算机科学教育新生态
数组版本
1 | struct SegmentTree |
指针版本
1 | struct SegmentTree |
合并线段树
雨天的尾巴 /【模板】线段树合并 - 洛谷 | 计算机科学教育新生态
对于动态开店的线段树,不能直接在两个线段树上按位相加,因为所对应的权值不一定相同,因此我们应当递归地合并线段树,根据子树情况维护。
简单来说分为三种情况,对于两颗线段树 来说,现在分别遍历到了 这两个节点,则有:
-
和 均为 ,合并后也不存在,返回即可。
-
或 其中一个非 ,此时只需要留下非 的点即可。
-
剩下的情况按位相加即可。
数组版本
1 | int merge(int x, int y, int l, int r) |
指针版本
1 | *Node merge(Node *x, Node *y, int l, int r) |
分裂线段树
P5494 【模板】线段树分裂 - 洛谷 | 计算机科学教育新生态
支持将一颗线段数(例如权值线段树)前 个权值分裂出来,类似线段树上二分,同样存在三种分讨。
1 | void split(int x, int &y, int k) |
1 | void split(Node *x, Node *&y, int k) |
可持久化线段树(主席树)
P3919 【模板】可持久化线段树 1(可持久化数组) - 洛谷 | 计算机科学教育新生态
一种支持查询历史版本的线段树类型,对于单点修改和单点查询有:
数组版本
1 | struct SegmentTree |
指针版本
1 | struct SegmentTree |
主函数中新建 root[]
存储每个历史版本的根。
1 | signed main() |
经典应用
静态区间 rank 问题
P3834 【模板】可持久化线段树 2 - 洛谷 | 计算机科学教育新生态
类似前缀和的思想,用边界的两棵树相减求出答案。
1 | int query(int x, int y, int l, int r, int k) |
1 | int query(Node *x, Node *y, int L, int R, int k) |
主函数:
1 | signed main() |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Thy's Blog!