Lam NguyenLibrary

Library · Data Structures · range queries

Segment Tree

#pragma once
#include <bits/stdc++.h>
using namespace std;

template <typename T>
struct SegmentTree {
    int N;
    vector<T> A;
    vector<T> st;

    SegmentTree(int n, const vector<T>& a) {
        N = n;
        A = a;
        st.resize(4 * N);
    }

    virtual T combine(const T& left, const T& right) = 0;
    virtual T identity() = 0;

    void build(int v, int tl, int tr) {
        if (tl == tr) {
            st[v] = A[tl];
            return;
        }
        int tm = tl + (tr - tl) / 2;
        build(v*2+1, tl, tm);
        build(v*2+2, tm+1, tr);
        st[v] = combine(st[v*2+1], st[v*2+2]);
    }

    T query(int v, int tl, int tr, int ql, int qr) {
        if (ql > qr) return identity();
        if (ql <= tl && tr <= qr) return st[v];
        int tm = tl + (tr - tl) / 2;
        T left = query(v*2+1, tl, tm, ql, min(tm, qr));
        T right = query(v*2+2, tm+1, tr, max(ql, tm+1), qr);
        return combine(left, right);
    }
};
class SegmentTree:
    # recursive, 0-indexed, with combine and identity passed in
    # (SegmentTree.h makes them virtual; here they are arguments)
    def __init__(self, a: list, combine=lambda x, y: x + y, identity=0):
        self.N = len(a)
        self.A = list(a)
        self.combine = combine
        self.identity = identity
        self.st = [identity] * (4 * max(self.N, 1))
        if self.N: self.build(0, 0, self.N - 1)

    def build(self, v: int, tl: int, tr: int) -> None:
        if tl == tr:
            self.st[v] = self.A[tl]
            return
        tm = tl + (tr - tl) // 2
        self.build(v * 2 + 1, tl, tm)
        self.build(v * 2 + 2, tm + 1, tr)
        self.st[v] = self.combine(self.st[v * 2 + 1], self.st[v * 2 + 2])

    # combine of a[ql..qr], inclusive
    def query(self, ql: int, qr: int, v: int = 0, tl: int = 0, tr: int = None):
        if tr is None: tr = self.N - 1
        if ql > qr: return self.identity
        if ql <= tl and tr <= qr: return self.st[v]
        tm = tl + (tr - tl) // 2
        left = self.query(ql, min(tm, qr), v * 2 + 1, tl, tm)
        right = self.query(max(ql, tm + 1), qr, v * 2 + 2, tm + 1, tr)
        return self.combine(left, right)

    # set a[pos] = x
    def update(self, pos: int, x, v: int = 0, tl: int = 0, tr: int = None) -> None:
        if tr is None: tr = self.N - 1
        if tl == tr:
            self.st[v] = x
            return
        tm = tl + (tr - tl) // 2
        if pos <= tm: self.update(pos, x, v * 2 + 1, tl, tm)
        else: self.update(pos, x, v * 2 + 2, tm + 1, tr)
        self.st[v] = self.combine(self.st[v * 2 + 1], self.st[v * 2 + 2])