线段树

进阶

线段树把一个大区间拆成很多可组合的小区间。

线段树

会展示数组被拆成哪些区间,以及一次区间查询如何下钻命中的节点。

AlgoAnim · 线段树

待机

速度
待机
// 源代码
1struct Node {
2    int l, r, sum;
3};
4
5vector<Node> seg;
6
7void pushUp(int p) {
8    seg[p].sum = seg[p << 1].sum + seg[p << 1 | 1].sum;
9}
10
11int query(int p, int ql, int qr) {
12    if (ql <= seg[p].l && seg[p].r <= qr) return seg[p].sum;
13    int mid = (seg[p].l + seg[p].r) >> 1;
14    int ans = 0;
15    if (ql <= mid) ans += query(p << 1, ql, qr);
16    if (qr > mid) ans += query(p << 1 | 1, ql, qr);
17    return ans;
18}

复杂度分析

时间 建树 O(n), 更新/查询 O(log n)
空间 O(n)
最优 O(log n)
最坏 O(log n)

算法讲解

线段树通过递归二分区间,把数组映射成一棵"节点负责一个区间"的树。

单点修改、区间查询、区间加法、区间赋值等问题,都可以通过节点信息合并来完成。

懒标记的意义在于"先记账,等真正访问到子区间时再下传",避免每次都更新整棵子树。

它是很多高级数据结构与算法优化的起点,值得尽早熟悉。