Atcoder AC Library 中的线段树(Segtree)数据结构详解
【免费下载链接】ac-library AtCoder Library 项目地址: https://gitcode.com/gh_mirrors/ac/ac-library
什么是线段树(Segtree)
线段树是Atcoder算法库(AC Library)中提供的一种高效处理区间查询的数据结构。它专门用于处理满足**幺半群(Monoid)**性质的代数结构,能够在O(log n)时间内完成单点更新和区间查询操作。
幺半群的基本概念
在正式介绍线段树之前,我们需要理解幺半群的概念。一个幺半群(S,·,e)由以下三部分组成:
- 集合S
- 二元运算·: S×S→S(满足结合律)
- 单位元e∈S(对于所有a∈S,有a·e = e·a = a)
常见的幺半群例子包括:
- 整数加法群:(Z,+,0)
- 整数乘法群:(Z,×,1)
- 最小值查询群:(Z,min,∞)
线段树的构造函数
AC Library中的线段树提供了两种初始化方式:
// 方式1:创建长度为n的线段树,所有元素初始化为e()
segtree<S, op, e> seg(n);
// 方式2:用已有vector初始化线段树
segtree<S, op, e> seg(v);
其中需要定义三个关键部分:
- 元素类型S
- 二元运算函数S op(S a, S b)
- 单位元函数S e()
例如,实现区间最小值查询(RMQ)的线段树可以这样定义:
int op(int a, int b) {
return min(a, b);
}
int e() {
return INT_MAX; // 足够大的值作为单位元
}
segtree<int, op, e> seg(10); // 创建10个元素的线段树
线段树的核心操作
单点更新(set)
void seg.set(int p, S x);
将位置p的元素更新为x,时间复杂度O(log n)。
单点查询(get)
S seg.get(int p);
获取位置p的元素值,时间复杂度O(1)。
区间查询(prod)
S seg.prod(int l, int r);
查询区间[l,r)内元素的op运算结果。如果l=r,返回e()。时间复杂度O(log n)。
全局查询(all_prod)
S seg.all_prod();
查询整个数组的op运算结果。时间复杂度O(1)。
高级操作:二分搜索
线段树还支持两种基于区间查询的二分搜索操作:
max_right
int seg.max_right<f>(int l);
从位置l开始,找到最大的r使得区间[l,r)满足条件f。要求f(e())=true且f具有单调性。
min_left
int seg.min_left<f>(int r);
从位置r开始向左,找到最小的l使得区间[l,r)满足条件f。同样要求f(e())=true且f具有单调性。
这两种操作的时间复杂度均为O(log n)。
实际应用示例
线段树可以解决多种区间查询问题,例如:
- 区间最小值/最大值查询
- 区间求和
- 区间GCD/LCM计算
- 区间矩阵乘法
- 动态统计满足某种条件的元素
性能分析
线段树的各种操作时间复杂度如下:
| 操作 | 时间复杂度 |
|---|---|
| 构造 | O(n) |
| set | O(log n) |
| get | O(1) |
| prod | O(log n) |
| all_prod | O(1) |
| max_right/min_left | O(log n) |
使用建议
- 确保定义的op运算确实满足结合律
- 正确实现单位元e(),保证其满足幺半群性质
- 对于复杂数据类型,注意op运算的时间复杂度
- 在需要频繁区间查询和单点更新的场景下优先考虑线段树
线段树是算法竞赛中极其重要的数据结构,掌握它能帮助你高效解决许多区间处理问题。AC Library提供的实现经过高度优化,可以直接在编程竞赛中使用。
【免费下载链接】ac-library AtCoder Library 项目地址: https://gitcode.com/gh_mirrors/ac/ac-library
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



