templates/sparse-table.cpp
compilable
$cat templates/sparse-table
Sparse Table
Static range query structure — O(1) for idempotent operations (min/max/gcd), O(log n) for non-idempotent.
#sparse-table#rmq#range-minimum#static
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>
struct MinOp {
constexpr T operator()(const T& a, const T& b) const { return a < b ? a : b; }
};
template <typename T = int, typename Op = MinOp<T>, int Base = 0, typename numsType = T>
class Sparse_Table {
private:
int n, LOG;
vector<vector<T>> table;
vector<int> Bin_Log;
Op operation;
T DEFAULT;
void Build_Table() {
for (int log = 1; log < LOG; log++)
for (int i = 1; i + (1 << log) - 1 <= n; i++)
table[i][log] =
operation(table[i][log - 1], table[i + (1 << (log - 1))][log - 1]);
}
T query_1(int L, int R) {
int log = Bin_Log[R - L + 1];
return operation(table[L][log], table[R - (1 << log) + 1][log]);
}
T query_log_n(int L, int R) {
T answer = DEFAULT;
for (int log = LOG; log >= 0; log--) {
if (L + (1 << log) - 1 <= R) {
answer = operation(answer, table[L][log]);
L += 1 << log;
}
}
return answer;
}
public:
Sparse_Table(int N = 0, const vector<numsType>& vec = vector<numsType>(),
Op op = Op{}, T def = numeric_limits<T>::max()) : n(N), LOG(__lg(n) + 1), operation(op), DEFAULT(def) {
table = vector<vector<T>>(n + 10, vector<T>(LOG, DEFAULT));
Bin_Log = vector<int>(n + 10);
for (int i = 2; i <= n; i++) Bin_Log[i] = Bin_Log[i >> 1] + 1;
for (int i = 1; i <= N; i++) table[i][0] = T(vec[i - !Base]);
Build_Table();
}
T query(int L, int R, bool is_overlap = false) {
return !is_overlap ? query_1(L, R) : query_log_n(L, R);
}
};
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;
}69 linesutf-8
$cat explanation_notes.md
notes_viewer --renderedmarkdown (math enabled)
Sparse Table — Static RMQ / Range Query
Quick Start (ECPC)
Range min, 0-indexed:
void Solve()
{
int n; cin >> n;
vector arr(n);
for (auto &x : arr) cin >> x; Sparse_Table st(n, arr);
int q; cin >> q;
while (q--) {
int l, r; cin >> l >> r;
cout << st.query(l, r) << "\n"; // O(1) min
}
}
Template Params
T — answer/value type (default int)Op — binary combine functor (default MinOp)Base — 0 = 0-indexed, 1 = 1-indexednumsType — input array type (default T)Constructor
Sparse_Table st(n, vec, op, def);
// n — array size
// vec — input array
// op — combine function (default: min)
// def — identity element (default: numeric_limits::max())
Methods
query(L, R) — O(1) range query (idempotent ops: min, max, gcd)query(L, R, true) — O(log n) range query (all ops: sum, etc.)Common Customizations
Range min (default):
Sparse_Table st(n, arr);
cout << st.query(l, r); // O(1)
Range max:
struct MaxOp { int operator()(int a, int b) const { return max(a, b); } };
Sparse_Table st(n, arr);
cout << st.query(l, r); // O(1)
Range sum (O(log n) queries):
auto sumOp = [](ll a, ll b){ return a + b; };
Sparse_Table st(n, arr, sumOp, 0LL);
cout << st.query(l, r, true); // must pass true
Notes
is_overlap = false (default): O(1), only for idempotent ops (min, max, gcd).is_overlap = true: O(log n), correct for all ops including sum.Base = 1 template param.