Segment Tree Template for Competitive Programming: Point Updates and Range Queries

The following reusable segment tree implementation uses 0-based indexing with half-open intervals [l, r). It supports point assignment, point addition, range queries, and methods to locate the first or last endex satisfying a custom predicate.

#include <bits/stdc++.h>

template<typename Info>
struct SegmentTree {
    int size = 0;
    std::vector<Info> data;

    void build(const std::vector<Info>& input) {
        build(input.data(), input.size());
    }

    template<typename T>
    void build(T* arr, int n) {
        size = n;
        int cap = 4 * (1 << (31 - __builtin_clz(n)));
        data.assign(cap, Info());

        std::function<void(int, int, int)> construct = [&](int node, int left, int right) {
            if (left + 1 == right) {
                data[node] = Info(arr[left]);
                return;
            }
            int mid = (left + right) / 2;
            construct(node * 2 + 1, left, mid);
            construct(node * 2 + 2, mid, right);
            merge(node);
        };
        construct(0, 0, size);
    }

    void merge(int node) {
        data[node] = data[node * 2 + 1] + data[node * 2 + 2];
    }

    void updatePoint(int node, int left, int right, int pos, const Info& value) {
        if (left + 1 == right) {
            data[node] = Info(value);
            return;
        }
        int mid = (left + right) / 2;
        if (pos < mid) updatePoint(node * 2 + 1, left, mid, pos, value);
        else updatePoint(node * 2 + 2, mid, right, pos, value);
        merge(node);
    }

    void updatePoint(int pos, const Info& value) {
        updatePoint(0, 0, size, pos, value);
    }

    void addValue(int node, int left, int right, int pos, const Info& value) {
        if (left + 1 == right) {
            data[node] += Info(value);
            return;
        }
        int mid = (left + right) / 2;
        if (pos < mid) addValue(node * 2 + 1, left, mid, pos, value);
        else addValue(node * 2 + 2, mid, right, pos, value);
        merge(node);
    }

    void addValue(int pos, const Info& value) {
        addValue(0, 0, size, pos, value);
    }

    Info queryRange(int node, int left, int right, int ql, int qr) {
        if (qr <= left || right <= ql) return Info();
        if (ql <= left && right <= qr) return data[node];
        int mid = (left + right) / 2;
        return queryRange(node * 2 + 1, left, mid, ql, qr) + 
               queryRange(node * 2 + 2, mid, right, ql, qr);
    }

    Info queryRange(int ql, int qr) {
        return queryRange(0, 0, size, ql, qr);
    }

    template<typename Pred>
    std::pair<int, Info> findFirstIndex(int node, int left, int right, int ql, int qr, Pred check) {
        if (qr <= left || right <= ql || !check(data[node])) return {-1, Info()};
        if (left + 1 == right) return {left, data[node]};
        int mid = (left + right) / 2;
        auto res = findFirstIndex(node * 2 + 1, left, mid, ql, qr, check);
        if (res.first == -1) res = findFirstIndex(node * 2 + 2, mid, right, ql, qr, check);
        return res;
    }

    template<typename Pred>
    std::pair<int, Info> findFirstIndex(int ql, int qr, Pred check) {
        return findFirstIndex(0, 0, size, ql, qr, check);
    }

    template<typename Pred>
    std::pair<int, Info> findLastIndex(int node, int left, int right, int ql, int qr, Pred check) {
        if (qr <= left || right <= ql || !check(data[node])) return {-1, Info()};
        if (left + 1 == right) return {left, data[node]};
        int mid = (left + right) / 2;
        auto res = findLastIndex(node * 2 + 2, mid, right, ql, qr, check);
        if (res.first == -1) res = findLastIndex(node * 2 + 1, left, mid, ql, qr, check);
        return res;
    }

    template<typename Pred>
    std::pair<int, Info> findLastIndex(int ql, int qr, Pred check) {
        return findLastIndex(0, 0, size, ql, qr, check);
    }
};

Problem 1A: Point Update and Range Sum

#include <bits/stdc++.h>
using ll = long long;

struct Node {
    ll total;
    Node() : total(0) {}
    Node(ll v) : total(v) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node(a.total + b.total);
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<ll> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);

    while (q--) {
        int type, l, r;
        std::cin >> type >> l >> r;
        if (type == 1) seg.updatePoint(l, r);
        else std::cout << seg.queryRange(l, r).total << '\n';
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 1B: Point Update and Range Minimum

#include <bits/stdc++.h>
using ll = long long;

struct Node {
    ll mn;
    Node() : mn(LLONG_MAX) {}
    Node(ll v) : mn(v) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node(std::min(a.mn, b.mn));
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<ll> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);

    while (q--) {
        int type, l, r;
        std::cin >> type >> l >> r;
        if (type == 1) seg.updatePoint(l, r);
        else std::cout << seg.queryRange(l, r).mn << '\n';
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 1C: Point Update, Range Min and Frequency

#include <bits/stdc++.h>
using ll = long long;

struct Node {
    int mini, freq;
    Node() : mini(INT_MAX), freq(0) {}
    Node(int v) : mini(v), freq(1) {}
    friend Node operator+(const Node& a, const Node& b) {
        if (a.mini < b.mini) return a;
        if (b.mini < a.mini) return b;
        return Node{a.mini, a.freq + b.freq};
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);

    while (q--) {
        int op, l, r;
        std::cin >> op >> l >> r;
        if (op == 1) seg.updatePoint(l, r);
        else {
            auto res = seg.queryRange(l, r);
            std::cout << res.mini << ' ' << res.freq << '\n';
        }
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 2A: Point Update and Maximum Subarray Sum

#include <bits/stdc++.h>
using ll = long long;

struct Node {
    ll pref, suff, full, best;
    Node() : pref(0), suff(0), full(0), best(0) {}
    Node(ll v) : pref(v), suff(v), full(v), best(std::max(0LL, v)) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node{
            std::max(a.pref, a.full + b.pref),
            std::max(b.suff, b.full + a.suff),
            a.full + b.full,
            std::max({a.best, b.best, a.suff + b.pref})
        };
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<ll> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);
    std::cout << seg.queryRange(0, n).best << '\n';

    while (q--) {
        int pos, val;
        std::cin >> pos >> val;
        seg.updatePoint(pos, val);
        std::cout << seg.queryRange(0, n).best << '\n';
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 2B: Point Toggle and Find k-th One in Binary String

#include <bits/stdc++.h>

struct Node {
    int ones;
    Node() : ones(0) {}
    Node(int v) : ones(v) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node(a.ones + b.ones);
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> s(n);
    for (auto& x : s) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(s);

    while (q--) {
        int type, val;
        std::cin >> type >> val;
        if (type == 1) {
            int cur = seg.queryRange(val, val + 1).ones;
            seg.updatePoint(val, 1 - cur);
        } else {
            int lo = 0, hi = n - 1, ans = -1;
            while (lo <= hi) {
                int mid = (lo + hi) / 2;
                if (seg.queryRange(0, mid + 1).ones >= val) {
                    ans = mid;
                    hi = mid - 1;
                } else lo = mid + 1;
            }
            std::cout << ans << '\n';
        }
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 2C: Point Update and Find First Index with Value >= X

#include <bits/stdc++.h>

struct Node {
    int peak;
    Node() : peak(INT_MIN) {}
    Node(int v) : peak(v) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node(std::max(a.peak, b.peak));
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);

    while (q--) {
        int op;
        std::cin >> op;
        if (op == 1) {
            int idx, val;
            std::cin >> idx >> val;
            seg.updatePoint(idx, val);
        } else {
            int target;
            std::cin >> target;
            auto res = seg.findFirstIndex(0, n, [&](const Node& nd) {
                return nd.peak >= target;
            });
            std::cout << res.first << '\n';
        }
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Problem 2D: Point Update and Find First Index >= X in Range [L, N)

#include <bits/stdc++.h>

struct Node {
    int peak;
    Node() : peak(INT_MIN) {}
    Node(int v) : peak(v) {}
    friend Node operator+(const Node& a, const Node& b) {
        return Node(std::max(a.peak, b.peak));
    }
};

void solve() {
    int n, q;
    std::cin >> n >> q;
    std::vector<int> arr(n);
    for (auto& x : arr) std::cin >> x;

    SegmentTree<Node> seg;
    seg.build(arr);

    while (q--) {
        int op, bound, target;
        std::cin >> op >> bound >> target;
        if (op == 1) {
            int idx, val;
            std::cin >> idx >> val;
            seg.updatePoint(idx, val);
        } else {
            auto res = seg.findFirstIndex(target, n, [&](const Node& nd) {
                return nd.peak >= bound;
            });
            std::cout << res.first << '\n';
        }
    }
}

int main() {
    std::cin.tie(nullptr)->sync_with_stdio(false);
    solve();
}

Tags: segment tree Competitive Programming Data Structures C++ range queries

Posted on Thu, 07 May 2026 09:24:23 +0000 by ainoy31