templates/segment-tree.cpp
compilable
$cat templates/segment-tree
Segment Tree
Classic segment tree with point update and range query for any associative operation.
#segment-tree#range-query#point-update
Log in to track progress, save custom versions, and organize into collections.Log In
$cat source_code/
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define sz(x) int(x.size())
template <typename T = int, typename Op = plus<T>, int Base = 0, typename numsType = T>
class Segment_Tree {
private:
int n, max_level;
T DEFAULT;
vector<T> tree;
Op operation;
void build(const vector<numsType>& nums, int idx, int lx, int rx) {
if (Base ? lx >= int(nums.size()) : lx > int(nums.size())) return;
if (rx == lx)
tree[idx] = T(nums[lx - !Base]);
else {
int mx = (rx + lx) / 2;
build(nums, idx * 2, lx, mx);
build(nums, idx * 2 + 1, mx + 1, rx);
tree[idx] = operation(tree[idx * 2], tree[idx * 2 + 1]);
}
}
void update(int index, numsType value, int idx, int lx, int rx) {
if (rx == lx)
tree[idx] = T(value);
else {
int mx = (rx + lx) / 2;
if (index <= mx)
update(index, value, idx * 2, lx, mx);
else
update(index, value, idx * 2 + 1, mx + 1, rx);
tree[idx] = operation(tree[idx * 2], tree[idx * 2 + 1]);
}
}
T query(int l, int r, int idx, int lx, int rx) const {
if (lx > r || l > rx) return DEFAULT;
if (lx >= l && rx <= r) return tree[idx];
int mx = (lx + rx) / 2;
return operation(query(l, r, idx * 2, lx, mx),
query(l, r, idx * 2 + 1, mx + 1, rx));
}
public:
Segment_Tree(int n = 0, const vector<numsType>& nums = vector<numsType>(),
Op op = Op{}, T def = T{})
: n(n), max_level(1), DEFAULT(def), operation(op) {
while ((1 << max_level) < n) max_level++;
tree = vector<T>(4 * n, DEFAULT);
if (!nums.empty()) build(nums, 1, 1, n);
}
// Rebuild from array — resets tree to DEFAULT first to avoid stale values
void build(const vector<numsType>& nums) {
std::fill(tree.begin(), tree.end(), DEFAULT);
build(nums, 1, 1, n);
}
void update(int index, numsType value) { update(index, value, 1, 1, n); }
T query(int l, int r) const { return query(l, r, 1, 1, n); }
T operator[](int index) const { return query(index, index, 1, 1, n); }
int size() const { return n; }
void print() const {
if (int(tree.size()) <= 1) return;
int level = 0;
queue<pair<int, int>> q;
q.push({1, level});
while (!q.empty()) {
int nodesAtCurrentLevel = q.size();
int spacesBetween = (1 << (max_level - level + 1)) - 1;
int leadingSpaces = (1 << (max_level - level)) - 1;
cout << string(leadingSpaces * 2, ' ');
while (nodesAtCurrentLevel--) {
auto [idx, lvl] = q.front();
q.pop();
cout << setw(2) << tree[idx];
if (nodesAtCurrentLevel) cout << string(spacesBetween * 2, ' ');
if (idx * 2 + 1 < int(tree.size())) {
q.push({idx * 2, lvl + 1});
q.push({idx * 2 + 1, lvl + 1});
}
}
cout << "\n";
level++;
}
}
};
void Solve() {
// write your code here
}
int main() {
ios_base::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int t = 1;
cin >> t;
while (t--) Solve();
return 0;
}107 linesutf-8
$cat explanation_notes.md
notes_viewer --renderedmarkdown (math enabled)
Segment Tree — Generic
Quick Start (ECPC)
Sum segment tree, 0-indexed input:
void Solve()
{
int n; cin >> n;
vector arr(n);
for (auto &x : arr) cin >> x; Segment_Tree<> seg(n, arr); // sum, 0-indexed
seg.update(3, 10); // set index 3 to 10
cout << seg.query(1, 5) << "\n"; // sum [1..5]
cout << seg[3] << "\n"; // single element
}
Max Segment Tree
struct MaxOp { int operator()(int a, int b) const { return max(a, b); } };void Solve()
{
int n; cin >> n;
vector arr(n);
for (auto &x : arr) cin >> x;
Segment_Tree seg(n, arr, MaxOp{}, INT_MIN);
cout << seg.query(1, n) << "\n"; // max in [1..n]
}
Template Params
T — node/answer type (default int)Op — binary combine functor (default plus)Base — 0 = 0-indexed, 1 = 1-indexednumsType — input array type (default T)Constructor
Segment_Tree seg(n, nums, op, def);
// n — array size
// nums — initial values (optional)
// op — combine function (optional)
// def — identity: 0 for sum, INT_MIN for max, INT_MAX for min, 0 for XOR
Methods
build(nums) — rebuild from arrayupdate(i, val) — point updatequery(l, r) — range queryseg[i] — single elementsize() — array sizeprint() — debug print treeNotes
Base.Base=0: seg.query(1, 5) queries indices 1..5 of your 0-indexed array.Base=1: seg.query(1, 5) queries indices 1..5 of your 1-indexed array.