Minimal, copy-paste C++ templates for common structures and patterns. Each snippet is self-contained and uses standard indexing.

Contents


Binary Search (Bounds)

Half-open range [lo, hi). Use when you need first ≥ x (lower_bound) or first > x (upper_bound).

// First index where a[i] >= x (lower_bound)
int lower_bound(const vector<int>& a, int x) {
    int lo = 0, hi = a.size();
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (a[mid] < x) lo = mid + 1;
        else hi = mid;
    }
    return lo;
}

// First index where a[i] > x (upper_bound)
int upper_bound(const vector<int>& a, int x) {
    int lo = 0, hi = a.size();
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (a[mid] <= x) lo = mid + 1;
        else hi = mid;
    }
    return lo;
}

// Binary search on answer: smallest x in [lo, hi] such that ok(x)
template<class F>
int bsearch_ans(int lo, int hi, F ok) {
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (ok(mid)) hi = mid;
        else lo = mid + 1;
    }
    return lo;
}
ID Title Link
34 Find First and Last Position Link
35 Search Insert Position Link
875 Koko Eating Bananas Link

Prefix Sum & Difference Array

Prefix sum: range sum in O(1). Difference array: range add in O(1), then one prefix sum to recover.

// Prefix sum: ps[i] = a[0]+...+a[i-1], sum(l,r) = ps[r+1]-ps[l]
vector<long long> prefix(const vector<int>& a) {
    vector<long long> ps(a.size() + 1);
    for (int i = 0; i < (int)a.size(); i++) ps[i + 1] = ps[i] + a[i];
    return ps;
}

// Difference array: for [l,r] += d do diff[l]+=d, diff[r+1]-=d; then partial_sum(diff) = values
void range_add(vector<long long>& diff, int l, int r, long long d) {
    diff[l] += d;
    if (r + 1 < (int)diff.size()) diff[r + 1] -= d;
}
// After all updates: partial_sum(diff.begin(), diff.end(), diff.begin());
ID Title Link
560 Subarray Sum Equals K Link
1109 Corporate Flight Bookings Link
1094 Car Pooling Link

Monotonic Stack

Maintain indices with strictly increasing (or decreasing) values. Use for next greater/smaller, or histogram rectangle.

// Next greater element (for each index)
vector<int> next_greater(const vector<int>& a) {
    int n = a.size();
    vector<int> ng(n, -1);
    vector<int> st;
    for (int i = 0; i < n; i++) {
        while (!st.empty() && a[st.back()] < a[i]) {
            ng[st.back()] = a[i];
            st.pop_back();
        }
        st.push_back(i);
    }
    return ng;
}

// Circular: wrap with 2*n and only push when i < n
vector<int> next_greater_circular(const vector<int>& a) {
    int n = a.size();
    vector<int> ng(n, -1);
    vector<int> st;
    for (int i = 0; i < 2 * n; i++) {
        int j = i % n;
        while (!st.empty() && a[st.back()] < a[j]) {
            ng[st.back()] = a[j];
            st.pop_back();
        }
        if (i < n) st.push_back(j);
    }
    return ng;
}
ID Title Link
739 Daily Temperatures Link
42 Trapping Rain Water Link
84 Largest Rectangle in Histogram Link
503 Next Greater Element II Link
1944 Visible People in Queue Link

Monotonic Queue

Deque of indices with values in monotonic order. Sliding window max/min.

// Sliding window maximum (window size k)
vector<int> max_sliding_window(const vector<int>& a, int k) {
    deque<int> dq;
    vector<int> out;
    for (int i = 0; i < (int)a.size(); i++) {
        while (!dq.empty() && a[dq.back()] <= a[i]) dq.pop_back();
        dq.push_back(i);
        if (dq.front() <= i - k) dq.pop_front();
        if (i >= k - 1) out.push_back(a[dq.front()]);
    }
    return out;
}
ID Title Link
239 Sliding Window Maximum Link
1438 Longest Continuous Subarray With Abs Diff ≤ Limit Link

Heap / Priority Queue

Min-heap: priority_queue<T, vector<T>, greater<T>>. K-way merge: push heads, pop min, push next from same list.

// K-way merge of sorted arrays (or list heads)
vector<int> merge_k_sorted(const vector<vector<int>>& lists) {
    using T = tuple<int, int, int>;
    priority_queue<T, vector<T>, greater<T>> pq;
    for (int i = 0; i < (int)lists.size(); i++)
        if (!lists[i].empty()) pq.emplace(lists[i][0], i, 0);
    vector<int> out;
    while (!pq.empty()) {
        auto [v, i, j] = pq.top();
        pq.pop();
        out.push_back(v);
        if (j + 1 < (int)lists[i].size()) pq.emplace(lists[i][j + 1], i, j + 1);
    }
    return out;
}
ID Title Link
23 Merge k Sorted Lists Link
295 Find Median from Data Stream Link

Union-Find (DSU)

Path compression + rank merge. find(x), unite(a,b).

struct DSU {
    vector<int> p, r;
    DSU(int n) : p(n), r(n, 0) { iota(p.begin(), p.end(), 0); }
    int find(int x) { return p[x] == x ? x : p[x] = find(p[x]); }
    bool unite(int a, int b) {
        a = find(a), b = find(b);
        if (a == b) return false;
        if (r[a] < r[b]) swap(a, b);
        p[b] = a;
        if (r[a] == r[b]) r[a]++;
        return true;
    }
};
ID Title Link
684 Redundant Connection Link
721 Accounts Merge Link
1319 Number of Operations to Make Network Connected Link

Trie

Fixed alphabet (e.g. 26). Insert and search in O( s ).
struct Trie {
    struct Node {
        int nxt[26];
        bool end = false;
        Node() { memset(nxt, -1, sizeof nxt); }
    };
    vector<Node> t{1};
    void insert(const string& s) {
        int u = 0;
        for (char c : s) {
            int i = c - 'a';
            if (t[u].nxt[i] == -1) { t[u].nxt[i] = t.size(); t.emplace_back(); }
            u = t[u].nxt[i];
        }
        t[u].end = true;
    }
    bool search(const string& s) {
        int u = 0;
        for (char c : s) {
            u = t[u].nxt[c - 'a'];
            if (u == -1) return false;
        }
        return t[u].end;
    }
};
ID Title Link
208 Implement Trie Link
211 Design Add and Search Words Link
212 Word Search II Link

Segment Tree

0-indexed range [0, n-1]. Point update, range sum (or min/max). Recursive implementation.

struct SegTree {
    int n;
    vector<long long> st;
    SegTree(int n) : n(n), st(4 * n, 0) {}
    void upd(int i, int l, int r, int p, long long v) {
        if (l == r) { st[i] = v; return; }
        int m = (l + r) / 2;
        if (p <= m) upd(2 * i, l, m, p, v);
        else upd(2 * i + 1, m + 1, r, p, v);
        st[i] = st[2 * i] + st[2 * i + 1];
    }
    long long qry(int i, int l, int r, int ql, int qr) {
        if (qr < l || r < ql) return 0;
        if (ql <= l && r <= qr) return st[i];
        int m = (l + r) / 2;
        return qry(2 * i, l, m, ql, qr) + qry(2 * i + 1, m + 1, r, ql, qr);
    }
    void upd(int p, long long v) { upd(1, 0, n - 1, p, v); }
    long long qry(int ql, int qr) { return qry(1, 0, n - 1, ql, qr); }
};
ID Title Link
307 Range Sum Query – Mutable Link
732 My Calendar III Link

Fenwick Tree (BIT)

1-indexed. Point add, prefix sum. Range sum [l, r] = sum(r) - sum(l-1).

struct BIT {
    int n;
    vector<long long> f;
    BIT(int n) : n(n), f(n + 1, 0) {}
    void add(int i, long long v) {
        for (; i <= n; i += i & -i) f[i] += v;
    }
    long long sum(int i) {
        long long s = 0;
        for (; i > 0; i -= i & -i) s += f[i];
        return s;
    }
    long long range_sum(int l, int r) { return sum(r) - sum(l - 1); }
};
ID Title Link
307 Range Sum Query – Mutable Link
315 Count of Smaller Numbers After Self Link
308 Range Sum Query 2D – Mutable Link

Sparse Table (Range Min/Max)

O(n log n) build, O(1) range min/max. Idempotent only (min, max, gcd). 0-indexed.

struct SparseTable {
    vector<vector<int>> st;
    vector<int> lg;
    int op(int a, int b) { return min(a, b); } // or max
    SparseTable(const vector<int>& a) {
        int n = a.size();
        lg.assign(n + 1, 0);
        for (int i = 2; i <= n; i++) lg[i] = lg[i / 2] + 1;
        int k = lg[n] + 1;
        st.assign(n, vector<int>(k));
        for (int i = 0; i < n; i++) st[i][0] = a[i];
        for (int j = 1; j < k; j++)
            for (int i = 0; i + (1 << j) <= n; i++)
                st[i][j] = op(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]);
    }
    int qry(int l, int r) {
        int j = lg[r - l + 1];
        return op(st[l][j], st[r - (1 << j) + 1][j]);
    }
};
ID Title Link
Range min/max, GCD (no update)

More Templates