Cartesian tree
A Cartesian tree arranges an array as a heap-ordered binary tree whose in-order reading is the array itself, so range minimum queries become lowest-common-ancestor queries.
Learning goals
- Define a Cartesian tree and state its two properties
- Build one in O(n) with a monotonic stack
- Reduce a range minimum query to finding a node in the tree
- Explain the link between RMQ and the lowest common ancestor
Prerequisites
A heap tells you the minimum, an array tells you the order. A Cartesian tree keeps both: the minimum is at the top, and reading the tree from left to right gives back the array.
RMQ reduction
In a min-heap-ordered Cartesian tree, the minimum of a[l..r] sits at the lowest common ancestor of the nodes l and r. To find it, start at the root and go down: if the current index is below l, every index in the range is in its right subtree; if it is above r, they are in its left subtree; the first index inside [l, r] is the answer.
Run the preset "Range minimum" (9 3 7 1 8 12 10 20, range [4, 7]): the animation walks down from the root (index 3, value 1), goes right once, and stops at index 4 with value 8. The walk is O(height) in the worst case, but the connection to O(1) queries is that the LCA problem has constant-time solutions.
1class CartesianRmq {2private final int[] left, right;3private final int root;4CartesianRmq(int[] a) {5int n = a.length;6left = new int[n]; right = new int[n];7Arrays.fill(left, -1); Arrays.fill(right, -1);8int[] stack = new int[n];9int top = 0;10for (int i = 0; i < n; i++) {11int last = -1;12while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top];13left[i] = last;14if (top > 0) right[stack[top - 1]] = i;15stack[top++] = i;16}17root = stack[0];18}19int argMin(int l, int r) { // index of the leftmost minimum in [l, r]20int v = root;21while (v < l || v > r) v = v < l ? right[v] : left[v];22return v;23}24}
Cartesian tree: monotonic-stack build and range minimum as an LCA
Interactive · edit the inputa[]
stack (indices, bottom to top)
A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down.
1int[] left, right; // child indices, -1 for none2int build(int[] a) { // min-heap Cartesian tree; returns the root3int n = a.length; left = new int[n]; right = new int[n];4Arrays.fill(left, -1); Arrays.fill(right, -1);5int[] stack = new int[n]; int top = 0;6for (int i = 0; i < n; i++) {7int last = -1;8while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top]; // larger values go below i, on its left9left[i] = last;10if (top > 0) right[stack[top - 1]] = i; // i hangs under the smaller value, on the right11stack[top++] = i;12}13return stack[0];14}15int rmq(int root, int l, int r) { // index of the minimum in [l, r]16int v = root; // the first node on the way down whose index lies in [l, r]17while (v < l || v > r) v = v < l ? right[v] : left[v];18return v;19}
Live state
n
8
Execution trace (dry run table)Show 14 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 | A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down. |
| 2 | L11 | i=0 value=9 left=none parent=none | Insert index 0 (9): its left child is empty, and it is the new root. |
| 3 | L8 | i=1 value=3 popped=0 | 9 (index 0) is larger than 3: pop it. It and everything popped before it will form the left subtree of index 1. |
| 4 | L11 | i=1 value=3 left=0 parent=none | Insert index 1 (3): its left child is index 0, and it is the new root. |
| 5 | L11 | i=2 value=7 left=none parent=1 | Insert index 2 (7): its left child is empty, and it becomes the right child of index 1 (3). |
| 6 | L8 | i=3 value=1 popped=2 | 7 (index 2) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 7 | L8 | i=3 value=1 popped=1 | 3 (index 1) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 8 | L11 | i=3 value=1 left=1 parent=none | Insert index 3 (1): its left child is index 1, and it is the new root. |
| 9 | L11 | i=4 value=8 left=none parent=3 | Insert index 4 (8): its left child is empty, and it becomes the right child of index 3 (1). |
| 10 | L11 | i=5 value=12 left=none parent=4 | Insert index 5 (12): its left child is empty, and it becomes the right child of index 4 (8). |
| 11 | L8 | i=6 value=10 popped=5 | 12 (index 5) is larger than 10: pop it. It and everything popped before it will form the left subtree of index 6. |
| 12 | L11 | i=6 value=10 left=5 parent=4 | Insert index 6 (10): its left child is index 5, and it becomes the right child of index 4 (8). |
| 13 | L11 | i=7 value=20 left=none parent=6 | Insert index 7 (20): its left child is empty, and it becomes the right child of index 6 (10). |
| 14 | L13 | return=3 pops=4 | The root is index 3 (value 1). Each index is pushed once and popped at most once, so the build is O(n) for 4 pops. |
Monotonic stack construction
Build the tree left to right with a stack holding the **right spine**: the path from the root going right, whose values increase from top of tree to bottom. For each new value, pop every larger value off the stack; the last popped one becomes the new node's left child. Then the new node becomes the right child of the value now on top, and is pushed.
Each index is pushed once and popped at most once, so the build is O(n). The preset "Build" with 9 3 7 1 8 12 10 20 makes 4 pops; "Sorted input: a long right spine" makes none, because every value is larger than the previous one and simply extends the spine. The code returns a parent array instead of child arrays, which is often all that is needed.
1static int[] parentArray(int[] a) { // parent[i] = index of i's parent in the min Cartesian tree, -1 for the root2int n = a.length;3int[] parent = new int[n];4Arrays.fill(parent, -1);5int[] stack = new int[n];6int top = 0;7for (int i = 0; i < n; i++) {8int last = -1;9while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top];10if (last >= 0) parent[last] = i; // the popped chain hangs under i on its left11if (top > 0) parent[i] = stack[top - 1]; // and i hangs under the smaller value on the right12stack[top++] = i;13}14return parent;15}
Cartesian tree: monotonic-stack build and range minimum as an LCA
Interactive · edit the inputa[]
stack (indices, bottom to top)
A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down.
1int[] left, right; // child indices, -1 for none2int build(int[] a) { // min-heap Cartesian tree; returns the root3int n = a.length; left = new int[n]; right = new int[n];4Arrays.fill(left, -1); Arrays.fill(right, -1);5int[] stack = new int[n]; int top = 0;6for (int i = 0; i < n; i++) {7int last = -1;8while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top]; // larger values go below i, on its left9left[i] = last;10if (top > 0) right[stack[top - 1]] = i; // i hangs under the smaller value, on the right11stack[top++] = i;12}13return stack[0];14}15int rmq(int root, int l, int r) { // index of the minimum in [l, r]16int v = root; // the first node on the way down whose index lies in [l, r]17while (v < l || v > r) v = v < l ? right[v] : left[v];18return v;19}
Live state
n
8
Execution trace (dry run table)Show 14 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 | A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down. |
| 2 | L11 | i=0 value=9 left=none parent=none | Insert index 0 (9): its left child is empty, and it is the new root. |
| 3 | L8 | i=1 value=3 popped=0 | 9 (index 0) is larger than 3: pop it. It and everything popped before it will form the left subtree of index 1. |
| 4 | L11 | i=1 value=3 left=0 parent=none | Insert index 1 (3): its left child is index 0, and it is the new root. |
| 5 | L11 | i=2 value=7 left=none parent=1 | Insert index 2 (7): its left child is empty, and it becomes the right child of index 1 (3). |
| 6 | L8 | i=3 value=1 popped=2 | 7 (index 2) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 7 | L8 | i=3 value=1 popped=1 | 3 (index 1) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 8 | L11 | i=3 value=1 left=1 parent=none | Insert index 3 (1): its left child is index 1, and it is the new root. |
| 9 | L11 | i=4 value=8 left=none parent=3 | Insert index 4 (8): its left child is empty, and it becomes the right child of index 3 (1). |
| 10 | L11 | i=5 value=12 left=none parent=4 | Insert index 5 (12): its left child is empty, and it becomes the right child of index 4 (8). |
| 11 | L8 | i=6 value=10 popped=5 | 12 (index 5) is larger than 10: pop it. It and everything popped before it will form the left subtree of index 6. |
| 12 | L11 | i=6 value=10 left=5 parent=4 | Insert index 6 (10): its left child is index 5, and it becomes the right child of index 4 (8). |
| 13 | L11 | i=7 value=20 left=none parent=6 | Insert index 7 (20): its left child is empty, and it becomes the right child of index 6 (10). |
| 14 | L13 | return=3 pops=4 | The root is index 3 (value 1). Each index is pushed once and popped at most once, so the build is O(n) for 4 pops. |
Cartesian tree properties
A Cartesian tree of an array has two properties. **Heap order**: every node is at most (for a min tree) its children. **In-order**: reading the tree in-order gives the indices 0, 1, 2, ..., n - 1, so the tree is a binary tree over the positions, not over the values. Together they determine the tree uniquely when values are distinct; with equal values a tie rule decides, and the stack code above keeps the earlier equal value above the later one.
More properties follow: the root is the (leftmost) minimum; the left subtree is the Cartesian tree of the part left of it and the right subtree that of the part right of it; the height equals the longest chain of nested minima. The preset "Repeated minimum" (5 2 7 2 9 2) shows the tie rule: the root is the first 2, at index 1, and the other 2s are on its right spine.
1static boolean isCartesianTree(int[] a, int[] left, int[] right, int root) {2int n = a.length;3List<Integer> order = new ArrayList<>();4if (!inorder(root, left, right, a, order, n)) return false;5for (int i = 0; i < n; i++) if (order.size() != n || order.get(i) != i) return false; // in-order must be 0..n-16return true;7}8private static boolean inorder(int v, int[] left, int[] right, int[] a, List<Integer> out, int n) {9if (v == -1) return true;10if (out.size() > n) return false; // guards against cycles11if (left[v] != -1 && a[left[v]] < a[v]) return false; // heap order12if (right[v] != -1 && a[right[v]] < a[v]) return false;13return inorder(left[v], left, right, a, out, n) && add(out, v) && inorder(right[v], left, right, a, out, n);14}15private static boolean add(List<Integer> out, int v) { out.add(v); return true; }
Cartesian tree: monotonic-stack build and range minimum as an LCA
Interactive · edit the inputa[]
stack (indices, bottom to top)
A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down.
1int[] left, right; // child indices, -1 for none2int build(int[] a) { // min-heap Cartesian tree; returns the root3int n = a.length; left = new int[n]; right = new int[n];4Arrays.fill(left, -1); Arrays.fill(right, -1);5int[] stack = new int[n]; int top = 0;6for (int i = 0; i < n; i++) {7int last = -1;8while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top]; // larger values go below i, on its left9left[i] = last;10if (top > 0) right[stack[top - 1]] = i; // i hangs under the smaller value, on the right11stack[top++] = i;12}13return stack[0];14}15int rmq(int root, int l, int r) { // index of the minimum in [l, r]16int v = root; // the first node on the way down whose index lies in [l, r]17while (v < l || v > r) v = v < l ? right[v] : left[v];18return v;19}
Live state
n
8
Execution trace (dry run table)Show 14 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 | A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down. |
| 2 | L11 | i=0 value=9 left=none parent=none | Insert index 0 (9): its left child is empty, and it is the new root. |
| 3 | L8 | i=1 value=3 popped=0 | 9 (index 0) is larger than 3: pop it. It and everything popped before it will form the left subtree of index 1. |
| 4 | L11 | i=1 value=3 left=0 parent=none | Insert index 1 (3): its left child is index 0, and it is the new root. |
| 5 | L11 | i=2 value=7 left=none parent=1 | Insert index 2 (7): its left child is empty, and it becomes the right child of index 1 (3). |
| 6 | L8 | i=3 value=1 popped=2 | 7 (index 2) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 7 | L8 | i=3 value=1 popped=1 | 3 (index 1) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 8 | L11 | i=3 value=1 left=1 parent=none | Insert index 3 (1): its left child is index 1, and it is the new root. |
| 9 | L11 | i=4 value=8 left=none parent=3 | Insert index 4 (8): its left child is empty, and it becomes the right child of index 3 (1). |
| 10 | L11 | i=5 value=12 left=none parent=4 | Insert index 5 (12): its left child is empty, and it becomes the right child of index 4 (8). |
| 11 | L8 | i=6 value=10 popped=5 | 12 (index 5) is larger than 10: pop it. It and everything popped before it will form the left subtree of index 6. |
| 12 | L11 | i=6 value=10 left=5 parent=4 | Insert index 6 (10): its left child is index 5, and it becomes the right child of index 4 (8). |
| 13 | L11 | i=7 value=20 left=none parent=6 | Insert index 7 (20): its left child is empty, and it becomes the right child of index 6 (10). |
| 14 | L13 | return=3 pops=4 | The root is index 3 (value 1). Each index is pushed once and popped at most once, so the build is O(n) for 4 pops. |
LCA connection
RMQ and the lowest common ancestor (LCA) are two views of one problem. RMQ on an array reduces to LCA in its Cartesian tree, as shown above. Conversely, LCA on any tree reduces to RMQ on the **Euler tour** depths: walk the tree, record the depth every time you enter a node or return to it, and note the first position of each node; the LCA of u and v is the node of minimum depth between their first positions.
Combining both with the sparse table gives an O(n log n) preprocessing and O(1) LCA queries. The class below does exactly that for a tree given by a parent array (with parent[i] < i), returning the lowest common ancestor by an O(1) argmin over the Euler tour.
1class LcaEuler {2private final int[] euler, first, depth;3private final int[][] idx; // sparse table of Euler positions by depth4LcaEuler(int[] parent) { // parent[0] = -1 and parent[i] < i5int n = parent.length;6List<List<Integer>> kids = new ArrayList<>();7for (int i = 0; i < n; i++) kids.add(new ArrayList<>());8depth = new int[n];9for (int i = 1; i < n; i++) { kids.get(parent[i]).add(i); depth[i] = depth[parent[i]] + 1; }10List<Integer> tour = new ArrayList<>();11first = new int[n];12Deque<int[]> stack = new ArrayDeque<>(); // {node, next child position}13stack.push(new int[]{0, 0});14first[0] = 0;15tour.add(0);16while (!stack.isEmpty()) {17int[] top = stack.peek();18if (top[1] < kids.get(top[0]).size()) {19int c = kids.get(top[0]).get(top[1]++);20first[c] = tour.size();21tour.add(c);22stack.push(new int[]{c, 0});23} else {24stack.pop();25if (!stack.isEmpty()) tour.add(stack.peek()[0]); // return to the parent26}27}28euler = tour.stream().mapToInt(Integer::intValue).toArray();29int m = euler.length, K = 32 - Integer.numberOfLeadingZeros(m);30idx = new int[K][];31idx[0] = new int[m];32for (int i = 0; i < m; i++) idx[0][i] = i;33for (int k = 1; k < K; k++) {34idx[k] = new int[m - (1 << k) + 1];35for (int i = 0; i + (1 << k) <= m; i++) {36int x = idx[k - 1][i], y = idx[k - 1][i + (1 << (k - 1))];37idx[k][i] = depth[euler[x]] <= depth[euler[y]] ? x : y;38}39}40}41int lca(int u, int v) {42int l = Math.min(first[u], first[v]), r = Math.max(first[u], first[v]);43int k = 31 - Integer.numberOfLeadingZeros(r - l + 1);44int x = idx[k][l], y = idx[k][r - (1 << k) + 1];45return euler[depth[euler[x]] <= depth[euler[y]] ? x : y];46}47}
Cartesian tree: monotonic-stack build and range minimum as an LCA
Interactive · edit the inputa[]
stack (indices, bottom to top)
A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down.
1int[] left, right; // child indices, -1 for none2int build(int[] a) { // min-heap Cartesian tree; returns the root3int n = a.length; left = new int[n]; right = new int[n];4Arrays.fill(left, -1); Arrays.fill(right, -1);5int[] stack = new int[n]; int top = 0;6for (int i = 0; i < n; i++) {7int last = -1;8while (top > 0 && a[stack[top - 1]] > a[i]) last = stack[--top]; // larger values go below i, on its left9left[i] = last;10if (top > 0) right[stack[top - 1]] = i; // i hangs under the smaller value, on the right11stack[top++] = i;12}13return stack[0];14}15int rmq(int root, int l, int r) { // index of the minimum in [l, r]16int v = root; // the first node on the way down whose index lies in [l, r]17while (v < l || v > r) v = v < l ? right[v] : left[v];18return v;19}
Live state
n
8
Execution trace (dry run table)Show 14 stepsHide
| Step | Line | State | What happens |
|---|---|---|---|
| 1 | L5 | n=8 | A Cartesian tree has the minimum at the root, the part left of it as the left subtree and the part right of it as the right subtree, recursively. The array order is the in-order order. A stack holds the right spine, whose values increase from the root down. |
| 2 | L11 | i=0 value=9 left=none parent=none | Insert index 0 (9): its left child is empty, and it is the new root. |
| 3 | L8 | i=1 value=3 popped=0 | 9 (index 0) is larger than 3: pop it. It and everything popped before it will form the left subtree of index 1. |
| 4 | L11 | i=1 value=3 left=0 parent=none | Insert index 1 (3): its left child is index 0, and it is the new root. |
| 5 | L11 | i=2 value=7 left=none parent=1 | Insert index 2 (7): its left child is empty, and it becomes the right child of index 1 (3). |
| 6 | L8 | i=3 value=1 popped=2 | 7 (index 2) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 7 | L8 | i=3 value=1 popped=1 | 3 (index 1) is larger than 1: pop it. It and everything popped before it will form the left subtree of index 3. |
| 8 | L11 | i=3 value=1 left=1 parent=none | Insert index 3 (1): its left child is index 1, and it is the new root. |
| 9 | L11 | i=4 value=8 left=none parent=3 | Insert index 4 (8): its left child is empty, and it becomes the right child of index 3 (1). |
| 10 | L11 | i=5 value=12 left=none parent=4 | Insert index 5 (12): its left child is empty, and it becomes the right child of index 4 (8). |
| 11 | L8 | i=6 value=10 popped=5 | 12 (index 5) is larger than 10: pop it. It and everything popped before it will form the left subtree of index 6. |
| 12 | L11 | i=6 value=10 left=5 parent=4 | Insert index 6 (10): its left child is index 5, and it becomes the right child of index 4 (8). |
| 13 | L11 | i=7 value=20 left=none parent=6 | Insert index 7 (20): its left child is empty, and it becomes the right child of index 6 (10). |
| 14 | L13 | return=3 pops=4 | The root is index 3 (value 1). Each index is pushed once and popped at most once, so the build is O(n) for 4 pops. |
Practice ladder
Now try it yourself
Easy
- Maximum Binary Tree
Medium
- Maximum Binary Tree II
- Lowest Common Ancestor of a Binary Tree
Advanced
- Largest Rectangle in Histogram (Cartesian tree view)
- Sum of Subarray Minimums
- Company Queries II (CSES)
Key takeaways
- A Cartesian tree is heap-ordered by value and in-order by index.
- A monotonic stack builds it in O(n): pop larger values to form the left child, hang the node under the smaller value.
- Range minimum = lowest common ancestor in the Cartesian tree; LCA = RMQ on the Euler tour depths.