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();
}