range queries on a static array, for idempotent operations. preprocessing and memory.

The structure

= the aggregate of the range .

const int LOG = 20;
int sp[LOG][MAXN], lg[MAXN];
 
void build(vector<int>& a) {
    int n = a.size();
    lg[1] = 0;
    for (int i = 2; i <= n; i++) lg[i] = lg[i/2] + 1;
    for (int i = 0; i < n; i++) sp[0][i] = a[i];
    for (int k = 1; k < LOG; k++)
        for (int i = 0; i + (1 << k) <= n; i++)
            sp[k][i] = min(sp[k-1][i], sp[k-1][i + (1 << (k-1))]);
}
 
int query(int l, int r) {                    // inclusive [l, r]
    int k = lg[r - l + 1];
    return min(sp[k][l], sp[k][r - (1 << k) + 1]);
}

The query covers with two overlapping blocks of length . Overlap is why the operation must be idempotent.

Idempotence — which operations work

Operation?Sparse table?
, yes
, yes (with a for the gcd itself)
bitwise AND, ORyes
, , XORno✘ — double-counts the overlap

For non-idempotent operations use a disjoint sparse table ( query, non-overlapping blocks) or a segment tree.

Choosing a range-query structure

UpdatesOperationStructureQuery
noneidempotentsparse table
noneany associativedisjoint sparse table
nonesumprefix sum
pointinvertibleFenwick
point/rangeany associativesegment tree
RMQ, buildFarach-Colton-Bender

Sparse tables are the right default whenever the array never changes: the constant factor is tiny and the code is fifteen lines.

Uses

  • LCA via Euler tour + RMQ on depths — the fastest practical LCA
  • LCP of arbitrary suffixes — RMQ over the LCP array
  • Range GCD queries
  • Binary lifting is structurally the same doubling table, applied to a tree instead of an array
  • Static range min for two-pointer / divide-and-conquer algorithms

2D sparse table

over rectangles of size . Build , query with four overlapping rectangles. Memory is the problem — a grid needs entries. Usually a sqrt decomposition or per-row sparse tables are more practical.

Memory

ints. For and that is 80 MB — often too much. Fixes: reduce LOG to , use int not long long, or switch to a segment tree ( memory, query).

See also: Disjoint Sparse Table · Segment Tree · Range Minimum Query