Maintain an entire convex piecewise-linear function in a pair of heaps, supporting the operations a DP needs in each. It turns a DP whose state is a function into one whose state is a data structure.

The representation

A convex piecewise-linear is determined by:

  • its minimum value ,
  • the multiset of slope-change points to the left of the minimum (kept in a max-heap ),
  • the multiset of slope-change points to the right (kept in a min-heap ).

Each breakpoint appears once per unit of slope change. Convexity guarantees .

The operations

OperationImplementationCost
push to both heaps, then rebalance; minf += max(0, L.top() - R.top())
push to only (with a rebalance)
push to only (with a rebalance)
minf += c
shift: lazy offsets on both heaps
prefix min: clear
suffix min: clear
sliding min: shift by , shift by
query the minimumminf
query at a pointsum the contributions — , rarely needed

Adding , concretely

priority_queue<long long> L;                                   // max-heap
priority_queue<long long, vector<long long>, greater<>> R;     // min-heap
long long addL = 0, addR = 0, minf = 0;
 
void addAbs(long long a) {
    L.push(a - addL);
    R.push(a - addR);
    long long l = L.top() + addL, r = R.top() + addR;
    if (l > r) {                                               // fix the ordering
        L.pop(); R.pop();
        L.push(r - addL); R.push(l - addR);
        minf += l - r;
    }
}

The minf += l - r line is the only place the minimum value changes, and it is exactly the amount by which the two pushed breakpoints were out of order.

The canonical problem

“Given , make the sequence non-decreasing with the minimum total .”

Define = minimum cost for the first elements with . Then

Each step is one “clear ” plus one “add ”. Total , and the answer is the final minf.

long long minCostNonDecreasing(vector<long long>& a) {
    priority_queue<long long> L;
    long long ans = 0;
    for (long long x : a) {
        L.push(x);
        if (L.top() > x) { ans += L.top() - x; L.pop(); L.push(x); }
    }
    return ans;
}

Eight lines, and it is one of the most striking algorithms in competitive programming — the heap disappears entirely because the prefix-min clears it every step.

For strictly increasing, subtract from each first; the problem becomes non-decreasing.

When it applies

Signal
The DP value as a function of one parameter is convexrequired
Transitions add , , or constants
Transitions take prefix/suffix minima or shift the function
You only need the final minimum, not the whole function
The function is not convex✘ — slope trick is invalid

Convexity is preserved by all the operations above, which is why the representation stays valid throughout.

TechniqueState is
Slope tricka convex piecewise-linear function, in heaps
CHTa set of lines, lower envelope
Li Chao treea set of lines, in a segment tree
Aliens tricka convex sequence indexed by a group count
”Segment tree beats” on a convex functiona function with range updates

All four exploit convexity; slope trick is the one that keeps the entire function around.

See also: Convex Hull Trick · Aliens Trick · Binary Heap