Given a static array, answer for many .

The methods

MethodPreprocessQuerySpaceNote
Naivefine for few queries
Precompute all
Sparse tablethe default
Segment treesupports updates
Sqrt decompositionsupports weird ops
Farach-Colton-Benderoptimal, big constant
Block + sparse table hybridthe practical version

Write the sparse table. Fifteen lines, queries, tiny constant.

int sp[LOG][MAXN], lg[MAXN];
void build(const vector<int>& a) {
    int n = a.size();
    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; (1 << k) <= n; 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
    int k = lg[r - l + 1];
    return min(sp[k][l], sp[k][r - (1 << k) + 1]);
}

The two blocks overlap, which is fine because min is idempotent. For non-idempotent operations use a disjoint sparse table.

The RMQ ↔ LCA equivalence

The two problems are interchangeable, and both directions are used:

LCA → RMQ. Take an Euler tour recording depths; is the minimum-depth entry between their first occurrences. Consecutive depths differ by , which is the ±1 RMQ special case that admits .

RMQ → LCA. Build the Cartesian tree of the array (a heap by value, a BST by index); then is the value at in that tree.

// Cartesian tree in O(n) with a monotonic stack
vector<int> par(n, -1), st;
for (int i = 0; i < n; i++) {
    int last = -1;
    while (!st.empty() && a[st.back()] > a[i]) { last = st.back(); st.pop_back(); }
    if (!st.empty()) par[i] = st.back();
    if (last != -1) par[last] = i;
    st.push_back(i);
}

This equivalence is why the result for ±1 RMQ gives for general RMQ: reduce to LCA, then back to ±1 RMQ.

The / construction

  1. Split into blocks of size .
  2. Sparse table over the block minima: .
  3. Within a block, the ±1 structure means only distinct block types exist; precompute every internal query for each type: .
  4. A query = suffix of one block + whole blocks + prefix of another.

See Farach-Colton-Bender. The constant is large; the sparse table beats it for every realistic .

Variants

VariantMethod
Range maxsame, flip the comparison
Range gcdsparse table (gcd is idempotent), per merge
Range sumprefix sum
With updatessegment tree
Range min indexstore indices in the table
-th smallest in a rangedifferent problem — persistent segment tree
Min over a tree pathbinary lifting or HLD
2D range min2D sparse table ( memory) or per-row tables
Min over all subarrays of a fixed lengthmonotonic deque,

Where RMQ appears as a subroutine

See also: Sparse Table · LCA · Farach-Colton-Bender