CSP-J/S · 数据结构

线段树 (Segment Tree)

区间改 + 区间查,都 O(log n)。关键直觉:递归到"区间被完全覆盖"就停下,区间修改在那里打一个懒标记

一、互动:一次区间操作只碰 O(log n) 个节点

这是 [1,8] 的线段树。输入区间 [x,y]query 看哪些节点被"完全覆盖"直接返回(绿)、哪些要继续递归(蓝);update 里被完全覆盖的节点改打懒标记(紫)。没被碰到的节点是灰的。

x y
完全覆盖 → 返回/打标记 部分重叠 → 继续递归 懒标记落点 未访问

二、模板核心:完全覆盖就停 + 懒标记

void update(int p, int l, int r, int x, int y, long long v) {  // [x,y] += v
    if (x <= l && r <= y) { sum[p] += v*(r-l+1); lazy[p] += v; return; }  // 完全覆盖→打懒标记
    pushdown(p, l, r);                       // 下行前把欠的标记传给孩子
    int m = (l + r) >> 1;
    if (x <= m) update(p<<1, l, m, x, y, v);
    if (y >  m) update(p<<1|1, m+1, r, x, y, v);
    sum[p] = sum[p<<1] + sum[p<<1|1];
}
long long query(int p, int l, int r, int x, int y) {
    if (x <= l && r <= y) return sum[p];      // 完全覆盖→直接返回
    pushdown(p, l, r);
    int m = (l + r) >> 1; long long res = 0;
    if (x <= m) res += query(p<<1, l, m, x, y);
    if (y >  m) res += query(p<<1|1, m+1, r, x, y);
    return res;
}

数组开 4n。只单点改区间查用 树状数组 更轻;静态区间最值用 ST 表

小结

① 结构
区间一分为二的二叉树,根管 [1,n],叶子管单点,树高 O(log n),数组开 4n。
② 完全覆盖就停
递归时区间被询问完全盖住就返回/打标记 —— 这保证每层只碰常数个节点。
③ 懒标记
区间改先在覆盖节点"欠着"记 lazy,下行前 pushdown 传给孩子。
④ 适用
区间改 + 区间查都 O(log n),比树状数组通用,但代码长、常数大。