线段树模版

本文最后更新于 7 个月前,文中所描述的信息可能已发生改变。

线段树模版

cpp
struct SGT {
    struct Node {
        int mx;   // 区间最大值
        int id;   // 最大值所在的下标
        int tag;  // 懒惰标记 (Lazy Tag)
    };

    int n;
    int st_idx; // 起始下标 (0 或 1)
    vector<Node> tree;

    // n: 数组长度, start_index: 你的数组下标是从 0 还是 1 开始
    SGT(int n, int start_index = 1) : n(n), st_idx(start_index) {
        tree.assign(4 * n + 1, {0, 0, 0});
    }
    
    void pushup(int v) {
        if (tree[v * 2].mx >= tree[v * 2 + 1].mx) {
            tree[v].mx = tree[v * 2].mx;
            tree[v].id = tree[v * 2].id;
        } else {
            tree[v].mx = tree[v * 2 + 1].mx;
            tree[v].id = tree[v * 2 + 1].id;
        }
    }

    void apply(int v, int val) {
        tree[v].mx += val;
        tree[v].tag += val;
    }

    void pushdown(int v) {
        if (tree[v].tag != 0) {
            apply(v * 2, tree[v].tag);
            apply(v * 2 + 1, tree[v].tag);
            tree[v].tag = 0;
        }
    }

    void build(int v, int l, int r, const vector<int>& vals) {
        if (l == r) {
            tree[v].mx = vals[l];
            tree[v].id = l;
            return;
        }
        int mid = (l + r) >> 1;
        build(v * 2, l, mid, vals);
        build(v * 2 + 1, mid + 1, r, vals);
        pushup(v);
    }

    void update(int v, int l, int r, int L, int R, int val) {
        if (L > R) return;
        if (l == L && r == R) {
            apply(v, val);
            return;
        }
        pushdown(v);
        int mid = (l + r) >> 1;
        if (L <= mid) update(v * 2, l, mid, L, min(mid, R), val);
        if (R > mid)  update(v * 2 + 1, mid + 1, r, max(mid + 1, L), R, val);
        pushup(v);
    }

    pair<int, int> query(int v, int l, int r, int L, int R) {
        if (L > R) return {LLONG_MIN, -1}; // 无效区间返回极小值
        if (l == L && r == R) return {tree[v].mx, tree[v].id};
        
        pushdown(v);
        int mid = (l + r) >> 1;
        
        if (R <= mid) return query(v * 2, l, mid, L, R);
        if (L > mid)  return query(v * 2 + 1, mid + 1, r, L, R);
        
        auto res_left = query(v * 2, l, mid, L, mid);
        auto res_right = query(v * 2 + 1, mid + 1, r, mid + 1, R);
        return res_left.first >= res_right.first ? res_left : res_right;
    }

    // [树上二分] 查询区间 [L, R] 内第一个大于等于 val 的元素下标
    int find_first(int v, int l, int r, int L, int R, int val) {
        if (L > R || tree[v].mx < val) return -1; // 剪枝
        if (l == r) return l; 
        
        pushdown(v);
        int mid = (l + r) >> 1;
        
        if (L <= mid) {
            int res = find_first(v * 2, l, mid, L, min(mid, R), val);
            if (res != -1) return res; 
        }
        if (R > mid) {
            return find_first(v * 2 + 1, mid + 1, r, max(mid + 1, L), R, val);
        }
        return -1;
    }

    
    void build_tree(const vector<int>& vals) {
        build(1, st_idx, st_idx + n - 1, vals);
    }

    void modify(int L, int R, int val) {
        update(1, st_idx, st_idx + n - 1, L, R, val);
    }

    pair<int, int> ask_max(int L, int R) {
        return query(1, st_idx, st_idx + n - 1, L, R);
    }
    
    int find_first_ge(int L, int R, int val) {
        return find_first(1, st_idx, st_idx + n - 1, L, R, val);
    }
};
Tarjan模版
可撤销并查集模版