线段树模板

本篇对应源码见仓库 solutions/xcpc/algorithm/ds/segment-tree/。

模板一

特点:

  • 单点更新,区间更新
  • push_down、push_up
  • 区间查询
  • 重载了两个update 与一个query

使用时注意:

  1. i 是节点编号,从 1 开始
  2. l, r 是区间端点,默认从 0 开始,如果要修改,需要修改 build 为 build(i, 1, n)
template<class T>
struct segmentTree {
    struct Node {
        int l, r;
        T sum;
        T lazy;
    };

    int n;
    vector<Node> tr;

    segmentTree(int _n) {
        init(vector<T> (_n));
    }
    segmentTree(vector<T> a) {
        init(a);
    }

    void init(vector<T> a) {
        n = a.size();
        tr.resize(n << 2, {});

        function<void(int, int, int)> build = [&](int i, int l, int r) -> void {
            tr[i].l = l, tr[i].r = r;
            if(l == r) {
                tr[i].sum = a[l];
                return;
            }
            int mid = l + ((r - l) >> 1);
            build(i << 1, l, mid);
            build(i << 1 | 1, mid + 1, r);
            push_up(i);
        };
        build(1, 0, n - 1);
    }

    void push_up(int i) {
        tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum;
    }
    void push_down(int i) {
        if(tr[i].lazy != 0) {
            int l = tr[i].l, r = tr[i].r;
            int mid = l + ((r - l) >> 1);

            tr[i << 1].sum += tr[i].lazy * (mid - tr[i << 1].l + 1);
            tr[i << 1].lazy += tr[i].lazy;

            tr[i << 1 | 1].sum += tr[i].lazy * (tr[i << 1 | 1].r - mid);
            tr[i << 1 | 1].lazy += tr[i].lazy;

            tr[i].lazy = 0;
        }
    }

    void update1(int i, int ind, T val) {
        int l = tr[i].l, r = tr[i].r;
        if(l == r) {
            tr[i].sum += val;
            return;
        }
        int mid = l + ((r - l) >> 1);
        if(ind <= mid) update1(i << 1, ind, val);
        else update1(i << 1 | 1, ind, val);
        push_up(i);
    }
    void update2(int i, int ul, int ur, T val) {
        int l = tr[i].l, r = tr[i].r;

        if(r < ul || l > ur) return;
        if(ul <= l && r <= ur) {
            // 打懒标记,无需再往后更新
            tr[i].sum += val * ((r - l) + 1);
            tr[i].lazy += val;
            return;
        }

        push_down(i);
        update2(i << 1, ul, ur, val);
        update2(i << 1 | 1, ul, ur, val);
        push_up(i);
    }

    T query(int i, int ql, int qr) {
        int l = tr[i].l, r = tr[i].r;

        if(r < ql || l > qr) return 0;
        if(ql <= l && r <= qr) return tr[i].sum;

        push_down(i);
        return query(i << 1, ql, qr) + query(i << 1 | 1, ql, qr);
    }

    void update(int ind, T val) {
        update1(1, ind, val);
    }
    void update(int ul, int ur, T val) {
        update2(1, ul, ur, val);
    }
    T query(int ql, int qr) {
        return query(1, ql, qr);
    }
};

模板二

特点:

  • 有两种区间修改操作:\(+,\ *\)
  • 所以对应两个懒标记
  • push_down 时都先处理 \(*\) ,然后处理 \(+\) (包括 \(sum,\ mul,\ add\))
template<class T>
struct segmentTree {
    struct Node {
        int l, r;
        T sum;
        T mul = 1, add = 0;
    };

    int n;
    vector<Node> tr;
    int mod;

    segmentTree(int _n) {
        init(vector<T> (_n));
    }
    segmentTree(vector<T> a, int p = MOD) {
        mod = p;
        init(a);
    }

    void init(vector<T> a) {
        n = a.size();
        tr.resize(n << 2);

        function<void(int, int, int)> build = [&](int i, int l, int r) -> void {
            tr[i].l = l, tr[i].r = r;
            if(l == r) {
                tr[i].sum = a[l] % mod;
                return;
            }
            int mid = l + (r - l >> 1);
            build(i << 1, l, mid);
            build(i << 1 | 1, mid + 1, r);
            push_up(i);
        };
        build(1, 0, n - 1);
    }

    void push_up(int i) {
        tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum;
        tr[i].sum %= mod;
    }
    void push_down(int i) {
        if(tr[i].add != 0 || tr[i].mul != 1) {
            int l = tr[i].l, r = tr[i].r;
            T mul = tr[i].mul, add = tr[i].add;
            int mid = l + (r - l >> 1);

            tr[i << 1].sum = (tr[i << 1].sum * mul % mod + add * (mid - l + 1) % mod) % mod;
            tr[i << 1].mul = tr[i << 1].mul * mul % mod;
            tr[i << 1].add = (tr[i << 1].add * mul % mod + add) % mod;

            tr[i << 1 | 1].sum = (tr[i << 1 | 1].sum * mul % mod + add * (r - mid) % mod) % mod;
            tr[i << 1 | 1].mul = tr[i << 1 | 1].mul * mul % mod;
            tr[i << 1 | 1].add = (tr[i << 1 | 1].add * mul % mod + add) % mod;

            tr[i].mul = 1;
            tr[i].add = 0;
        }
    }

    // void update1(int i, int ind, T val) {
    //     int l = tr[i].l, r = tr[i].r;
    //     if(l == r) {
    //         tr[i].sum += val;
    //         return;
    //     }
    //     int mid = l + (r - l >> 1);
    //     if(ind <= mid) update1(i << 1, ind, val);
    //     else update1(i << 1 | 1, ind, val);
    //     push_up(i);
    // }
    void update2(int i, int ul, int ur, T val, int op) {
        int l = tr[i].l, r = tr[i].r;

        if(r < ul || l > ur) return;
        if(ul <= l && r <= ur) {
            // 打懒标记,无需再往后更新
            if(op == 1) {
                tr[i].sum = tr[i].sum * val % mod;
                tr[i].mul = tr[i].mul * val % mod;
                tr[i].add = tr[i].add * val % mod;
            } else if(op == 2) {
                tr[i].sum = (tr[i].sum + val * (r - l + 1)) % mod;
                tr[i].add = (tr[i].add + val ) % mod;
            }
            return;
        }

        push_down(i);
        int mid = l + (r - l >> 1);
        update2(i << 1, ul, ur, val, op);
        update2(i << 1 | 1, ul, ur, val, op);
        push_up(i);
    }

    T query(int i, int ql, int qr) {
        int l = tr[i].l, r = tr[i].r;

        if(r < ql || l > qr) return 0;
        if(ql <= l && r <= qr) return tr[i].sum;

        push_down(i);
        return (query(i << 1, ql, qr) + query(i << 1 | 1, ql, qr)) % mod;
    }

    void update1(int ind, T val) {
        update1(1, ind, val);
    }
    void update2(int ul, int ur, T val, int op) {
        update2(1, ul, ur, val, op);
    }
    T query(int ql, int qr) {
        return query(1, ql, qr);
    }
};

signed main() {
    IOS;

    int n, q, m;
    cin >> n >> q >> m;
    vector<ll> arr(n);
    fer(i, 0, n) cin >> arr[i];

    segmentTree seg(arr, m);
    while(q--) {
        int op;
        cin >> op;
        if(op == 3) {
            int x, y;
            cin >> x >> y;
            cout << seg.query(x - 1, y - 1) << '\n';
        } else {
            int x, y, k;
            cin >> x >> y >> k;
            seg.update2(x - 1, y - 1, k, op);
        }
    }

    return 0;
}
posted @ 2026-11-11 06:23  slowbyte  阅读(3)  评论(0)    收藏  举报