LIS (Patience Trick)

O(n log n)

Longest strictly increasing subsequence. tails[k] holds the smallest possible last element of an increasing subsequence of length k+1; each new element replaces the first tail that is >= it (binary search), or extends the array. The tails array is always sorted, which is what makes the binary search valid, but note it is NOT itself the subsequence. Use lower_bound for strictly increasing, upper_bound to allow ties.

// use it on

CSES: Increasing Subsequence

The template verbatim: read the array, print lis(a). n is 2·10^5, so the O(n²) table DP would time out.

// the code

int lis(vector<int>& a) {
    vector<int> tails;  // tails[k] = smallest tail of an LIS of length k+1
    for (int x : a) {
        auto it = lower_bound(tails.begin(), tails.end(), x);
        if (it == tails.end()) tails.push_back(x);
        else *it = x;
    }
    return tails.size();
}

// to recover one LIS, also record for each element the length it achieved,
// then walk backwards taking the first element with length L, L-1, ...

// more classics