DSA DSA In Depth
0%
lesson cartesian-treermqmonotonic-stack

Cartesian Trees: Linear-Time Monotonic Stack Construction & RMQ-LCA Duality

7 min read Module 3.3: Range Query & Sublinear Decomposition Structures Updated Oct 23, 2026
📄 Cheat Sheet
Range Minima & Cartesian Trees: RMQ-LCA Duality and O(N) Construction
Sebastian Wild (Lectures) Range Minima & Cartesian Trees: RMQ-LCA Duality and O(N) Construction Watch on YouTube ↗

Concise derivation of how a Cartesian Tree encodes array indices in-order and values in min-heap order, reducing Range Minimum Queries to Lowest Common Ancestor.

0:00 / --:--

1. Linear-Time $\Theta(N)$ Right-Spine Construction via Monotonic Stack

Suppose we have already built the Cartesian tree for prefix $A[0..i-1]$. Because index $i$ is larger than every index in ${0, \dots, i-1}$, node $i$ must be placed somewhere along the rightmost spine of the current tree (and cannot have a right child yet). As we climb up the right spine from the bottommost node, any spine node $s$ with $A[s] > A[i]$ violates the min-heap invariant if $s$ remains above $i$. Therefore:

  1. Pop all nodes $s$ from the right-spine stack that have $A[s] > A[i]$; let $last$ be the last node popped (the shallowest popped node with $A[last] > A[i]$).
  2. Make $last$ the left child of $i$ (left[i] = last), preserving the inorder requirement because all indices in $last$'s subtree are $< i$.
  3. If the stack is still non-empty, its top node $p$ satisfies $A[p] \le A[i]$; attach $i$ as the right child of $p$ (right[p] = i). Push $i$ onto the right-spine stack.

Because each index $i \in [0, N-1]$ is pushed onto the right-spine stack once and popped at most once, the entire construction runs in at most $2N$ stack operations—exact $\Theta(N)$ time!

Cartesian Tree — Treap — Quicksort — RMQ-LCA Isomorphism:
  • RMQ $\iff$ LCA Duality: For any $0 \le L \le R < N$, $\arg\min_{i \in [L, R]} A[i] = \text{LCA}_{\text{Cartesian}(A)}(L, R)$. Furthermore, node $i$'s subtree covers the exact maximal contiguous subarray $[L_i, R_i]$ around $i$ where $A[i]$ is the minimum—the foundation of the $O(N)$ Largest Rectangle in a Histogram algorithm!
  • Treap Isomorphism: A Treap with keys $0, 1, \dots, N-1$ and random priorities $P[i]$ is literally the Cartesian tree of $P$.
Cartesian Tree Right-Spine Insertion: Inserting A[5] = 4 into A = [9, 3, 7, 1, 8, 4] 1. Before i=5: Right Spine = [i=3(1), i=4(8)] 3:1 1:3 0:9 2:7 4:8 2. Pop 4:8 (> 4), make 4:8 left child of 5:4, attach 5:4 to 3:1 3:1 1:3 0:9 2:7 5:4 4:8 RMQ(1, 5) = LCA(node 1, node 5) = node 3 (value 1) | Subtree of 1:3 is [0..2]
flowchart LR RMQ["General Static RMQ on A[0..N-1]"] -->|"O(N) Monotonic Stack"| CT["Cartesian Tree T(A)"] CT -->|"O(N) Euler Tour"| PM1["±1 RMQ on Depth Array D[0..2N-2]"] PM1 -->|"Four Russians Block Lookup"| O1["Theta(N) Build, Theta(1) Query RMQ!"]
Hardware & Cache Reality — Flat Pre-Allocated Stack & Zero-Allocation Construction: Using a single pre-allocated Int32Array(n) as the right-spine stack and Int32Array(n) for parent, left, and right builds the Cartesian tree of $10^7$ integers in ~35 milliseconds in V8/C++—completely dominated by sequential L1 cache streaming with zero dynamic allocations.
Heavy-Light Decomposition, Cartesian Tree Stack & Mo’s Snake-Order Sweep
O((N+Q)√N) Mo · O(log² N) HLD · O(N) Cartesian

Switch between three foundational range-query reductions: (1) Mo’s offline √N block-snake query ordering, (2) Heavy-Light path decomposition into ≤ 2 log₂ N contiguous Segment Tree intervals, and (3) O(N) Monotonic Stack Cartesian Tree construction.

Step 1 / 8
Custom Input:
Timeline

Invariant & State

Step 1 (Even Block 0): Queries with L ∈ Block 0 are sorted by R ascending. curR sweeps right monotonically (6 → 7) in O(N) total steps for the block.
🌳 Live 2D Hierarchical Tree Topology — Heavy-Light Decomposition, Cartesian Tree Stack & Mo’s Snake-Order Sweep Visited/Active Pivot/Root Resolved
Even Blo Q1:[1… [0] curR adv Q2:[0… [1] Q3:[3… [2] Q4:[4… [3]
[0]Q1:[1, 6] (blk 0, R↑)Even Block 0: Sweep R Ascending (6 → 7)
[1]Q2:[0, 7] (blk 0, R↑)curR advances +1
[2]Q3:[3, 5] (blk 1, R↓)
[3]Q4:[4, 2] (blk 1, R↓)
Optimal Block Size B
B = max(1, ⌊N / √Q⌋)
Left Pointer Moves
≤ Q · B = O(N√Q)
Right Pointer Moves
≤ (N/B) · N = O(N√Q)
[Step 1] In Even Block 0, curR moves right from 6 to 7 (+1 step) while curL jitters within Block 0 by at most B = √N steps.

2. Production Implementation: $\Theta(N)$ Cartesian Tree & All-Subarray-Minimums Summation

/**
 * Constructs the Min-Cartesian Tree of arr[0..N-1] in exact Theta(N) time
 * using a monotonic right-spine stack.
 * Ties broken by smaller index (arr[stack[top]] > arr[i] pops strictly greater values).
 */
function buildCartesianTree(arr) {
  const n = arr.length;
  const parent = new Int32Array(n).fill(-1);
  const left = new Int32Array(n).fill(-1);
  const right = new Int32Array(n).fill(-1);
  const stack = new Int32Array(n);
  let top = -1;

  for (let i = 0; i < n; i++) {
    let lastPopped = -1;
    // Pop nodes from right spine that are strictly greater than arr[i]
    while (top >= 0 && arr[stack[top]] > arr[i]) {
      lastPopped = stack[top--];
    }
    // The shallowest popped node becomes the left child of i
    if (lastPopped !== -1) {
      left[i] = lastPopped;
      parent[lastPopped] = i;
    }
    // If stack is non-empty, i becomes the right child of stack[top]
    if (top >= 0) {
      right[stack[top]] = i;
      parent[i] = stack[top];
    }
    stack[++top] = i;
  }

  // The root of the entire Cartesian tree is at the bottom of the right spine (stack[0])
  const root = n > 0 ? stack[0] : -1;
  return { root, parent, left, right };
}

/**
 * Application: Sum of min(A[L..R]) over all N*(N+1)/2 subarrays in O(N) time!
 * In the Cartesian tree, node i is the minimum for all subarrays [L, R]
 * where L is in i's left subtree (+ i) and R is in i's right subtree (+ i).
 */
function sumOfSubarrayMinimums(arr) {
  const n = arr.length;
  const { root, left, right } = buildCartesianTree(arr);
  const sz = new Int32Array(n);
  let totalSum = 0;

  // Iterative post-order traversal
  const order = [];
  const stack = root !== -1 ? [root] : [];
  while (stack.length > 0) {
    const u = stack.pop();
    order.push(u);
    if (left[u] !== -1) stack.push(left[u]);
    if (right[u] !== -1) stack.push(right[u]);
  }

  for (let idx = order.length - 1; idx >= 0; idx--) {
    const u = order[idx];
    const szL = left[u] !== -1 ? sz[left[u]] : 0;
    const szR = right[u] !== -1 ? sz[right[u]] : 0;
    sz[u] = 1 + szL + szR;
    totalSum += arr[u] * (szL + 1) * (szR + 1);
  }
  return totalSum;
}

3. Complexity Matrix

Problem / Transformation Naive / Divide & Conquer Via Cartesian Tree Space Overhead
Build Min/Max Cartesian Tree $O(N^2)$ worst-case without RMQ $\Theta(N)$ (at most $2N$ stack ops) $3N$ integers (left, right, parent)
Reduce General RMQ to $\pm 1$ RMQ — $\Theta(N)$ via Cartesian Tree + Euler Tour $\Theta(N)$
Sum of $\min(A[L..R])$ / Largest Histogram Area $O(N^2)$ $\Theta(N)$ via subtree sizes $(sz_L + 1)(sz_R + 1)$ $\Theta(N)$
Common Pitfall — Duplicate Values & Strict vs Non-Strict Inequality on the Spine: When $A$ contains duplicate values ($A[j] = A[i]$ for $j < i$), using strict inequality arr[stack[top]] > arr[i] keeps the earlier index $j$ above $i$ (breaking ties to the left, so each duplicate range is counted exactly once in sumOfSubarrayMinimums). If you use >= in one place and > in another, duplicate subarrays will be either double-counted or skipped!
Check yourself Question 1 of 4
Concept Check Defining Properties of a Cartesian Tree recall

Given an array $A[0..N-1]$ of distinct numbers, what two simultaneous invariants uniquely define its Min-Cartesian Tree?

⚡ Interactive Challenge · Staff Level

Algorithmic Design & Complexity Check

Analyze the invariant, asymptotic bound, and hardware behavior before selecting.

How many distinct Cartesian Tree topologies exist for a block of $b$ elements, and how does this allow encoding any block's RMQ structure without requiring the $\pm 1$ adjacent-difference property?

Key Takeaways

A Cartesian tree for A[0..N-1] is a binary tree that is simultaneously a BST on array indices (inorder traversal is 0..N-1) and a min-heap on array values A[i].
Maintaining the right spine on a monotonic stack builds the Cartesian tree in exact Theta(N) time because every node is pushed once and popped at most once.
RMQ(L, R) on array A is identical to LCA(L, R) in the Cartesian tree of A, completing the bidirectional linear-time equivalence between RMQ and LCA.
In the Cartesian tree, the subtree rooted at i spans the exact maximal interval [L_i, R_i] where A[i] is the minimum, so A[i] is the minimum of (sz[left[i]] + 1) * (sz[right[i]] + 1) subarrays.
Was this lesson helpful? Spot an issue or have a suggestion? Let us know on GitHub.
Report an issue