Problem. For each element of an array, find the first element to its right that is strictly greater (or if none).

Monotonic stack —

vector<int> nextGreater(const vector<int>& a) {
    int n = a.size();
    vector<int> res(n, -1);
    stack<int> st;                                   // indices, decreasing values
    for (int i = 0; i < n; i++) {
        while (!st.empty() && a[st.top()] < a[i]) {
            res[st.top()] = a[i];                    // i is the answer for st.top()
            st.pop();
        }
        st.push(i);
    }
    return res;
}

Each index is pushed once and popped once, so the total is despite the inner while. The stack holds exactly the indices still waiting for an answer — those whose value has not yet been exceeded.

The four directions

WantDirectionPop while
Next greaterleft to righta[st.top()] < a[i]
Next smallerleft to righta[st.top()] > a[i]
Previous greaterleft to right, read the top before pushinga[st.top()] <= a[i]
Previous smallerleft to right, read the top before pushinga[st.top()] >= a[i]

For “previous”, read st.top() before pushing ; for “next”, assign the answer while popping.

Strict vs non-strict (< vs <=) decides how ties are handled — and it matters. When counting “subarrays where this element is the minimum”, use strict on one side and non-strict on the other so that equal elements are attributed to exactly one of them.

Circular version

Traverse the array twice, using indices mod :

for (int i = 0; i < 2 * n; i++) {
    while (!st.empty() && a[st.top()] < a[i % n]) { res[st.top()] = a[i % n]; st.pop(); }
    if (i < n) st.push(i);                           // only push during the first pass
}

Pushing only in the first pass prevents duplicate entries.

What it unlocks

ProblemUses
Largest rectangle in a histogramprevious and next smaller
Maximal rectangle in a binary matrixthe above, per row
Trapping rain waternext greater on both sides
Sum of subarray minimumscount where each element is the minimum
Sum of subarray rangesmax-sum minus min-sum
Stock spanprevious greater
Daily temperaturesnext greater (distance)
Remove digits for the smallest numbergreedy with a stack
Build a Cartesian tree in the stack is the right spine
Count visible bars from the leftprevious greater
Convex hull (monotone chain)the same “pop while the turn is wrong” discipline

Counting subarrays where each element dominates

// for each i: subarrays in which a[i] is the minimum
long long total = 0;
for (int i = 0; i < n; i++)
    total += (long long)a[i] * (i - prevSmaller[i]) * (nextSmaller[i] - i);

This contribution technique converts an enumeration over subarrays into over elements, and it generalises to sums of maxima, of ranges, and of gcds.

The Cartesian tree connection

Building a Cartesian tree (heap by value, BST by index) with a monotonic stack is :

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);
}

The stack is the right spine of the tree being built. This gives the RMQ ↔ LCA reduction in linear time, and explains why the monotonic stack and the Cartesian tree keep appearing in the same problems.

Why it is worth knowing

The monotonic stack is the answer to an entire class of “for each element, find the nearest element satisfying X” questions, and the amortized argument (“each element is pushed and popped once”) is the cleanest example of aggregate analysis.

See also: Monotonic Stack · Largest Rectangle · Range Minimum Query