C++ Competitive Programming Template - Everything in One Place
Boilerplate
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define F first
#define S second
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define sz(x) (int)(x).size()
#define rep(i, a, b) for(int i = a; i < b; i++)
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef vector<pii> vii;
const int INF = 1e18;
const int MOD = 1e9 + 7;
const int N = 2e5 + 5;
const int LG = 20;
int n, m;
void solve() {
// solution here
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 1;
// cin >> t;
while(t--) solve();
return 0;
}
DSU (Disjoint Set Union / Union-Find)
struct DSU {
int connected;
int par[N], sz[N];
DSU() {}
DSU(int n) {
for(int i = 1; i <= n; i++) {
par[i] = i;
sz[i] = 1;
}
connected = n;
}
int getPar(int k) {
while(k != par[k]) {
par[k] = par[par[k]]; // path compression (halving)
k = par[k];
}
return k;
}
bool same(int u, int v) {
return getPar(u) == getPar(v);
}
int getSize(int k) {
return sz[getPar(k)];
}
// returns false if already connected
bool unite(int u, int v) {
int p1 = getPar(u), p2 = getPar(v);
if(p1 == p2) return false;
connected--;
if(sz[p1] > sz[p2]) swap(p1, p2);
sz[p2] += sz[p1];
sz[p1] = 0;
par[p1] = p2;
return true;
}
};
// DSU dsu(n);
// dsu.unite(u, v);
// dsu.same(u, v);
// dsu.connected — number of connected components
Segment Tree (Range Query, Range Update, Lazy Propagation)
Customize data, merge, and propagate for the problem. This version does range-assign + range-min query.
struct node {
int mn;
node() : mn(1e9) {}
};
struct SegTree {
int N;
vector<node> st;
vector<bool> hasLazy;
vector<int> lazy;
void init(int n) {
N = n;
st.resize(4 * N + 5);
hasLazy.assign(4 * N + 5, false);
lazy.assign(4 * N + 5, 0);
}
void merge(node &cur, node &l, node &r) {
cur.mn = min(l.mn, r.mn);
}
void applyLazy(int node, int L, int R) {
st[node].mn = lazy[node];
if(L != R) {
hasLazy[2*node] = hasLazy[2*node+1] = true;
lazy[2*node] = lazy[2*node+1] = lazy[node];
}
hasLazy[node] = false;
}
void push(int node, int L, int R) {
if(hasLazy[node]) applyLazy(node, L, R);
}
void build(int node, int L, int R, vector<int> &a) {
if(L == R) { st[node].mn = a[L]; return; }
int M = (L + R) / 2;
build(2*node, L, M, a);
build(2*node+1, M+1, R, a);
merge(st[node], st[2*node], st[2*node+1]);
}
node query(int node, int L, int R, int l, int r) {
push(node, L, R);
if(r < L || R < l) return node{}; // identity
if(l <= L && R <= r) return st[node];
int M = (L + R) / 2;
node left = query(2*node, L, M, l, r);
node right = query(2*node+1, M+1, R, l, r);
node cur;
merge(cur, left, right);
return cur;
}
void update(int node, int L, int R, int l, int r, int val) {
push(node, L, R);
if(r < L || R < l) return;
if(l <= L && R <= r) {
hasLazy[node] = true;
lazy[node] = val;
applyLazy(node, L, R);
return;
}
int M = (L + R) / 2;
update(2*node, L, M, l, r, val);
update(2*node+1, M+1, R, l, r, val);
merge(st[node], st[2*node], st[2*node+1]);
}
// public interface
void build(vector<int> &a) { build(1, 1, N, a); }
node query(int l, int r) { return query(1, 1, N, l, r); }
void update(int l, int r, int v) { update(1, 1, N, l, r, v); }
void update(int pos, int v) { update(1, 1, N, pos, pos, v); }
};
// SegTree seg; seg.init(n); seg.build(a);
// seg.query(l, r).mn
// seg.update(l, r, val) — range assign
// seg.update(pos, val) — point assign
Sum + range-add lazy (very common variant):
struct SegTreeSum {
int N;
vector<long long> st, lazy;
void init(int n) {
N = n;
st.assign(4 * N + 5, 0);
lazy.assign(4 * N + 5, 0);
}
void push(int node, int L, int R) {
if(lazy[node]) {
int M = (L + R) / 2;
st[2*node] += lazy[node] * (M - L + 1);
st[2*node+1] += lazy[node] * (R - M);
lazy[2*node] += lazy[node];
lazy[2*node+1] += lazy[node];
lazy[node] = 0;
}
}
void build(int node, int L, int R, vector<int> &a) {
if(L == R) { st[node] = a[L]; return; }
int M = (L + R) / 2;
build(2*node, L, M, a);
build(2*node+1, M+1, R, a);
st[node] = st[2*node] + st[2*node+1];
}
long long query(int node, int L, int R, int l, int r) {
if(r < L || R < l) return 0;
if(l <= L && R <= r) return st[node];
push(node, L, R);
int M = (L + R) / 2;
return query(2*node, L, M, l, r) + query(2*node+1, M+1, R, l, r);
}
void update(int node, int L, int R, int l, int r, long long val) {
if(r < L || R < l) return;
if(l <= L && R <= r) {
st[node] += val * (R - L + 1);
lazy[node] += val;
return;
}
push(node, L, R);
int M = (L + R) / 2;
update(2*node, L, M, l, r, val);
update(2*node+1, M+1, R, l, r, val);
st[node] = st[2*node] + st[2*node+1];
}
void build(vector<int> &a) { build(1, 1, N, a); }
long long query(int l, int r) { return query(1, 1, N, l, r); }
void update(int l, int r, long long v) { update(1, 1, N, l, r, v); }
void update(int pos, long long v) { update(1, 1, N, pos, pos, v); }
};
// SegTreeSum seg; seg.init(n); seg.build(a);
// seg.query(l, r) — range sum
// seg.update(l, r, val) — range add
// seg.update(pos, val) — point add
Fenwick Tree (BIT)
struct BIT {
int N;
vector<int> bit;
void init(int n) {
N = n;
bit.assign(n + 1, 0);
}
void update(int idx, int val) {
for(; idx <= N; idx += idx & -idx)
bit[idx] += val;
}
int pref(int idx) {
int ans = 0;
for(; idx > 0; idx -= idx & -idx)
ans += bit[idx];
return ans;
}
int query(int l, int r) {
return pref(r) - pref(l - 1);
}
// point update, then range min/max (non-reversible — use only for prefix max)
void updateMax(int idx, int val) {
for(; idx <= N; idx += idx & -idx)
bit[idx] = max(bit[idx], val);
}
int prefMax(int idx) {
int ans = -2e9;
for(; idx > 0; idx -= idx & -idx)
ans = max(ans, bit[idx]);
return ans;
}
};
// BIT bit; bit.init(n);
// bit.update(i, val); bit.query(l, r);
Range update + point query (difference array BIT):
struct BITDiff {
int N;
vector<long long> bit;
void init(int n) { N = n; bit.assign(n + 2, 0); }
void update(int idx, long long val) {
for(; idx <= N; idx += idx & -idx)
bit[idx] += val;
}
long long pref(int idx) {
long long ans = 0;
for(; idx > 0; idx -= idx & -idx)
ans += bit[idx];
return ans;
}
void rangeAdd(int l, int r, long long val) {
update(l, val);
update(r + 1, -val);
}
long long pointQuery(int i) { return pref(i); }
};
// BITDiff bit; bit.init(n);
// bit.rangeAdd(l, r, val); bit.pointQuery(i);
Sparse Table (Static RMQ, O(1) query)
int floorlog[N];
int sparse[20][N]; // sparse[j][i] = min of [i, i + 2^j - 1]
void buildSparse(vector<int> &a, int n) {
for(int i = 2; i <= n; i++)
floorlog[i] = floorlog[i/2] + 1;
for(int i = 1; i <= n; i++) sparse[0][i] = a[i];
for(int j = 1; (1 << j) <= n; j++)
for(int i = 1; i + (1 << j) - 1 <= n; i++)
sparse[j][i] = min(sparse[j-1][i], sparse[j-1][i + (1 << (j-1))]);
}
int rmq(int l, int r) {
int k = floorlog[r - l + 1];
return min(sparse[k][l], sparse[k][r - (1 << k) + 1]);
}
// Change min -> max for range max. O(n log n) build, O(1) query, no updates.
Dijkstra
vector<pii> g[N]; // g[u] = {v, weight}
int dist[N];
void dijkstra(int src) {
fill(dist + 1, dist + n + 1, INF);
dist[src] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({0, src});
while(!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if(d > dist[u]) continue;
for(auto [v, w] : g[u]) {
if(dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
pq.push({dist[v], v});
}
}
}
}
// dist[v] = INF means unreachable
With path reconstruction:
int par[N];
void dijkstra(int src) {
fill(dist+1, dist+n+1, INF);
fill(par+1, par+n+1, -1);
dist[src] = 0;
priority_queue<pii, vector<pii>, greater<pii>> pq;
pq.push({0, src});
while(!pq.empty()) {
auto [d, u] = pq.top(); pq.pop();
if(d > dist[u]) continue;
for(auto [v, w] : g[u]) {
if(dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
par[v] = u;
pq.push({dist[v], v});
}
}
}
}
vector<int> getPath(int t) {
vector<int> path;
for(int v = t; v != -1; v = par[v]) path.pb(v);
reverse(all(path));
return path;
}
BFS (Unweighted Shortest Path)
int bfsDist[N];
int bfsPar[N];
void bfs(int src) {
fill(bfsDist+1, bfsDist+n+1, -1);
fill(bfsPar+1, bfsPar+n+1, -1);
queue<int> q;
bfsDist[src] = 0;
q.push(src);
while(!q.empty()) {
int u = q.front(); q.pop();
for(auto v : g[u]) {
if(bfsDist[v] == -1) {
bfsDist[v] = bfsDist[u] + 1;
bfsPar[v] = u;
q.push(v);
}
}
}
}
0-1 BFS (edge weights 0 or 1):
void bfs01(int src) {
fill(dist+1, dist+n+1, INF);
dist[src] = 0;
deque<int> dq;
dq.push_front(src);
while(!dq.empty()) {
int u = dq.front(); dq.pop_front();
for(auto [v, w] : g[u]) {
if(dist[u] + w < dist[v]) {
dist[v] = dist[u] + w;
if(w == 0) dq.push_front(v);
else dq.push_back(v);
}
}
}
}
Multi-source BFS: push all sources at distance 0 before starting.
Floyd-Warshall (All-Pairs Shortest Path)
int dist[505][505];
void floydWarshall(int n) {
// init: dist[i][i] = 0, dist[i][j] = edge weight or INF
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
if(dist[i][k] < INF && dist[k][j] < INF)
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}
// After: if dist[i][i] < 0, there is a negative cycle reachable from i.
// Use n <= 500 only.
Bellman-Ford (Negative Weights / Negative Cycle Detection)
struct Edge { int u, v, w; };
vector<Edge> edges;
int dist[N];
bool bellmanFord(int src, int n) { // returns true if negative cycle exists
fill(dist+1, dist+n+1, INF);
dist[src] = 0;
for(int i = 0; i < n - 1; i++)
for(auto &[u, v, w] : edges)
if(dist[u] < INF && dist[u] + w < dist[v])
dist[v] = dist[u] + w;
// nth iteration — if any update, negative cycle exists
for(auto &[u, v, w] : edges)
if(dist[u] < INF && dist[u] + w < dist[v])
return true;
return false;
}
Topological Sort (Kahn’s, lexicographically smallest)
int indeg[N];
vector<int> g[N];
vector<int> topoSort(int n) {
for(int u = 1; u <= n; u++)
for(auto v : g[u]) indeg[v]++;
priority_queue<int, vi, greater<int>> pq; // min-heap for lex smallest
for(int i = 1; i <= n; i++)
if(!indeg[i]) pq.push(i);
vector<int> order;
while(!pq.empty()) {
int u = pq.top(); pq.pop();
order.pb(u);
for(auto v : g[u])
if(--indeg[v] == 0) pq.push(v);
}
if(sz(order) < n) return {}; // cycle exists
return order;
}
Kruskal’s MST
struct Edge { int u, v, w; };
int kruskalMST(int n, vector<Edge> &edges) {
sort(all(edges), [](auto &a, auto &b){ return a.w < b.w; });
DSU dsu(n);
int cost = 0, cnt = 0;
for(auto &[u, v, w] : edges) {
if(dsu.unite(u, v)) {
cost += w;
if(++cnt == n - 1) break;
}
}
return (cnt == n - 1) ? cost : -1; // -1 if not connected
}
Strongly Connected Components (Kosaraju’s)
vector<int> g[N], rg[N];
bool vis[N];
vector<int> order;
int comp[N];
int numSCC;
void dfs1(int u) {
vis[u] = true;
for(auto v : g[u]) if(!vis[v]) dfs1(v);
order.pb(u);
}
void dfs2(int u, int c) {
comp[u] = c;
for(auto v : rg[u]) if(comp[v] == -1) dfs2(v, c);
}
void scc(int n) {
for(int i = 1; i <= n; i++) if(!vis[i]) dfs1(i);
fill(comp+1, comp+n+1, -1);
numSCC = 0;
for(int i = n - 1; i >= 0; i--) // process in reverse finish order
if(comp[order[i]] == -1) dfs2(order[i], numSCC++);
}
void addEdge(int u, int v) {
g[u].pb(v);
rg[v].pb(u);
}
// comp[u] = SCC id of u (0-indexed). numSCC = total SCCs.
// nodes in same SCC have same comp value.
Articulation Points & Bridges
int tin[N], low[N], timer_ap;
bool vis[N], isAP[N];
vector<int> g[N];
vector<pii> bridges; // {u, v}
void dfs(int u, int par) {
vis[u] = true;
tin[u] = low[u] = ++timer_ap;
int children = 0;
for(auto v : g[u]) {
if(v == par) continue;
if(vis[v]) {
low[u] = min(low[u], tin[v]);
} else {
dfs(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= tin[u] && par != -1) isAP[u] = true;
if(low[v] > tin[u]) bridges.pb({u, v}); // bridge
children++;
}
}
if(par == -1 && children > 1) isAP[u] = true;
}
void findAPBridges(int n) {
timer_ap = 0;
for(int i = 1; i <= n; i++)
if(!vis[i]) dfs(i, -1);
}
// Note: for multigraphs, track edge index instead of parent node to avoid
// treating parallel edges as back edges.
LCA (Binary Lifting)
int par[LG][N], tin[N], tout[N], level[N], lca_timer;
vector<int> g[N];
void dfs(int u, int p, int lvl) {
tin[u] = ++lca_timer;
par[0][u] = p;
level[u] = lvl;
for(auto v : g[u]) if(v != p) dfs(v, u, lvl + 1);
tout[u] = lca_timer;
}
void buildLCA(int root, int n) {
lca_timer = 0;
dfs(root, root, 0);
for(int i = 1; i < LG; i++)
for(int j = 1; j <= n; j++)
par[i][j] = par[i-1][par[i-1][j]];
}
bool isAnc(int u, int v) { // is u an ancestor of v?
return tin[u] <= tin[v] && tout[v] <= tout[u];
}
int lca(int u, int v) {
if(isAnc(u, v)) return u;
if(isAnc(v, u)) return v;
for(int i = LG-1; i >= 0; i--)
if(!isAnc(par[i][u], v)) u = par[i][u];
return par[0][u];
}
int kthAncestor(int u, int k) { // k-th ancestor of u
for(int i = LG-1; i >= 0; i--)
if((k >> i) & 1) u = par[i][u];
return u;
}
int dist(int u, int v) {
return level[u] + level[v] - 2 * level[lca(u, v)];
}
// buildLCA(1, n) — call once after building the tree in g[]
KMP (Pattern Matching)
vector<int> prefixFunction(const string &s) {
int n = s.size();
vector<int> pi(n, 0);
for(int i = 1; i < n; i++) {
int j = pi[i-1];
while(j > 0 && s[i] != s[j]) j = pi[j-1];
if(s[i] == s[j]) j++;
pi[i] = j;
}
return pi;
}
// returns 0-indexed positions in text where pattern starts
vector<int> kmpSearch(const string &text, const string &pattern) {
string s = pattern + '#' + text;
auto pi = prefixFunction(s);
vector<int> matches;
int p = pattern.size();
for(int i = p + 1; i < (int)s.size(); i++)
if(pi[i] == p) matches.pb(i - 2 * p);
return matches;
}
// period of string s: if (n % (n - pi[n-1])) == 0, period = n - pi[n-1]
Z-Algorithm
vector<int> zFunction(const string &s) {
int n = s.size();
vector<int> z(n, 0);
z[0] = n;
for(int i = 1, l = 0, r = 0; i < n; i++) {
if(i <= r) z[i] = min(r - i + 1, z[i - l]);
while(i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
}
return z;
}
// Pattern matching: s = pattern + '#' + text
// positions i in text where z[i] == |pattern|
Polynomial String Hashing (Double Hash)
struct Hash {
static const int MOD1 = 1e9 + 7, MOD2 = 1e9 + 9;
static const int B1 = 131, B2 = 137;
vector<long long> h1, h2, p1, p2;
void build(const string &s) {
int n = s.size();
h1.resize(n+1, 0); h2.resize(n+1, 0);
p1.resize(n+1, 1); p2.resize(n+1, 1);
for(int i = 0; i < n; i++) {
h1[i+1] = (h1[i] * B1 + s[i]) % MOD1;
h2[i+1] = (h2[i] * B2 + s[i]) % MOD2;
p1[i+1] = p1[i] * B1 % MOD1;
p2[i+1] = p2[i] * B2 % MOD2;
}
}
pair<long long,long long> get(int l, int r) { // 0-indexed [l, r]
long long v1 = (h1[r+1] - h1[l] * p1[r-l+1] % MOD1 + MOD1 * 2) % MOD1;
long long v2 = (h2[r+1] - h2[l] * p2[r-l+1] % MOD2 + MOD2 * 2) % MOD2;
return {v1, v2};
}
};
// Hash h; h.build(s); h.get(l, r) == h.get(l2, r2) → substrings equal
Trie (Binary / XOR Trie)
struct Trie {
struct Node {
int ch[2] = {0, 0};
int cnt = 0;
};
vector<Node> t;
int root;
Trie() { t.push_back(Node()); root = 0; }
void insert(int x, int BITS = 30) {
int cur = root;
for(int i = BITS; i >= 0; i--) {
int b = (x >> i) & 1;
if(!t[cur].ch[b]) {
t[cur].ch[b] = t.size();
t.push_back(Node());
}
cur = t[cur].ch[b];
t[cur].cnt++;
}
}
void remove(int x, int BITS = 30) {
int cur = root;
for(int i = BITS; i >= 0; i--) {
cur = t[cur].ch[(x >> i) & 1];
t[cur].cnt--;
}
}
int maxXor(int x, int BITS = 30) {
int cur = root, ans = 0;
for(int i = BITS; i >= 0; i--) {
int b = (x >> i) & 1;
int want = 1 - b;
if(t[cur].ch[want] && t[t[cur].ch[want]].cnt > 0) {
ans |= (1 << i);
cur = t[cur].ch[want];
} else {
cur = t[cur].ch[b];
}
}
return ans;
}
int minXor(int x, int BITS = 30) {
int cur = root, ans = 0;
for(int i = BITS; i >= 0; i--) {
int b = (x >> i) & 1;
if(t[cur].ch[b] && t[t[cur].ch[b]].cnt > 0)
cur = t[cur].ch[b];
else {
ans |= (1 << i);
cur = t[cur].ch[1-b];
}
}
return ans;
}
};
Modular Arithmetic
const int MOD = 1e9 + 7;
int pw(long long a, long long b, long long mod = MOD) {
int ans = 1;
a %= mod;
while(b > 0) {
if(b & 1) ans = (__int128)ans * a % mod;
a = (__int128)a * a % mod;
b >>= 1;
}
return ans;
}
int modinv(int a, int mod = MOD) {
return pw(a, mod - 2, mod); // only for prime mod
}
int add(int a, int b, int mod = MOD) { return (a + b) % mod; }
int sub(int a, int b, int mod = MOD) { return ((a - b) % mod + mod) % mod; }
int mul(int a, int b, int mod = MOD) { return (long long)a * b % mod; }
// --- nCr precomputation ---
int fact[N], inv_fact[N];
void precompFact(int n) {
fact[0] = 1;
for(int i = 1; i <= n; i++) fact[i] = mul(fact[i-1], i);
inv_fact[n] = modinv(fact[n]);
for(int i = n-1; i >= 0; i--) inv_fact[i] = mul(inv_fact[i+1], i+1);
}
int nCr(int n, int r) {
if(r < 0 || r > n) return 0;
return mul(fact[n], mul(inv_fact[r], inv_fact[n-r]));
}
// precompFact(N-1) once in main, then nCr(n, r) in O(1)
Matrix Exponentiation
const int SZ = 2; // matrix dimension — change per problem
struct Matrix {
long long a[SZ][SZ];
Matrix() { memset(a, 0, sizeof(a)); }
Matrix operator*(const Matrix &o) const {
Matrix res;
for(int i = 0; i < SZ; i++)
for(int k = 0; k < SZ; k++) if(a[i][k])
for(int j = 0; j < SZ; j++)
res.a[i][j] = (res.a[i][j] + a[i][k] * o.a[k][j]) % MOD;
return res;
}
};
Matrix identity() {
Matrix I;
for(int i = 0; i < SZ; i++) I.a[i][i] = 1;
return I;
}
Matrix matpow(Matrix M, long long p) {
Matrix res = identity();
while(p > 0) {
if(p & 1) res = res * M;
M = M * M;
p >>= 1;
}
return res;
}
// Use: encode F(n) = M * F(n-1), then F(n) = matpow(M, n) * F(0)
// Fibonacci: M = [[1,1],[1,0]], F(0) = [1, 0]
Digit DP
// Count integers in [0, R] satisfying property P.
// For [L, R]: f(R) - f(L-1).
// State: (position, tight, ...property-specific state)
// Example: count numbers in [0, R] with at most 3 non-zero digits
// Adapt state dimensions to the problem (here: pos, tight, nonzero_count)
int digits[20], sz;
int cache[20][2][11]; // [pos][tight][nonzero_count], adjust last dim per problem
int dp(int idx, bool tight, int nonzero) {
if(nonzero > 3) return 0;
if(idx == sz) return 1;
int &ans = cache[idx][tight][nonzero];
if(ans != -1) return ans;
ans = 0;
int hi = tight ? digits[idx] : 9;
for(int d = 0; d <= hi; d++)
ans += dp(idx + 1, tight && (d == hi), nonzero + (d > 0));
return ans;
}
int f(long long R) {
if(R < 0) return 0;
sz = 0;
while(R > 0) { digits[sz++] = R % 10; R /= 10; }
reverse(digits, digits + sz);
memset(cache, -1, sizeof(cache));
return dp(0, true, 0);
}
// answer for [L, R] = f(R) - f(L - 1)
Monotone Stack
// Next Greater Element (to the right)
vector<int> nextGreater(vector<int> &a) {
int n = a.size();
vector<int> ans(n, -1);
stack<int> st; // stores indices
for(int i = 0; i < n; i++) {
while(!st.empty() && a[st.top()] < a[i]) {
ans[st.top()] = i; // or a[i] for the value
st.pop();
}
st.push(i);
}
return ans; // ans[i] = index of next greater element, -1 if none
}
// Previous Smaller Element (to the left) — iterate right-to-left and flip condition
// Largest rectangle in histogram uses two monotone stack passes (or one pass)
int largestRectangle(vector<int> &h) {
int n = h.size();
stack<int> st;
int ans = 0;
h.pb(0); // sentinel
for(int i = 0; i <= n; i++) {
while(!st.empty() && h[st.top()] > h[i]) {
int height = h[st.top()]; st.pop();
int width = st.empty() ? i : i - st.top() - 1;
ans = max(ans, height * width);
}
st.push(i);
}
return ans;
}
Sliding Window Maximum (Monotone Deque)
vector<int> slidingMax(vector<int> &a, int k) {
deque<int> dq; // stores indices, front = current max
vector<int> ans;
for(int i = 0; i < (int)a.size(); i++) {
while(!dq.empty() && dq.front() < i - k + 1) dq.pop_front();
while(!dq.empty() && a[dq.back()] <= a[i]) dq.pop_back();
dq.push_back(i);
if(i >= k - 1) ans.pb(a[dq.front()]);
}
return ans;
}
Common DP Patterns
Longest Increasing Subsequence (O(n log n))
int lis(vector<int> &a) {
vector<int> dp; // dp[i] = smallest tail of IS of length i+1
for(int x : a) {
auto it = lower_bound(all(dp), x); // use upper_bound for non-strict
if(it == dp.end()) dp.pb(x);
else *it = x;
}
return dp.size();
}
0/1 Knapsack
// n items, capacity W, weights w[], values v[]
vector<int> knapsack(int n, int W, vector<int> &w, vector<int> &v) {
vector<int> dp(W + 1, 0);
for(int i = 0; i < n; i++)
for(int j = W; j >= w[i]; j--) // iterate down for 0/1
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
return dp; // dp[W] = max value with capacity W
}
// Unbounded knapsack: iterate j upward
Bitmask DP (TSP template)
// dp[mask][i] = min cost to visit exactly nodes in mask, ending at i
int tsp(int n, vector<vector<int>> &cost) {
int FULL = (1 << n) - 1;
vector<vector<int>> dp(1 << n, vector<int>(n, INF));
dp[1][0] = 0; // start at node 0
for(int mask = 1; mask <= FULL; mask++) {
for(int u = 0; u < n; u++) {
if(!(mask & (1 << u)) || dp[mask][u] == INF) continue;
for(int v = 0; v < n; v++) {
if(mask & (1 << v)) continue;
int nmask = mask | (1 << v);
dp[nmask][v] = min(dp[nmask][v], dp[mask][u] + cost[u][v]);
}
}
}
int ans = INF;
for(int u = 1; u < n; u++)
ans = min(ans, dp[FULL][u] + cost[u][0]);
return ans;
}
Sum over Subsets (SOS DP)
// dp[mask] = sum of f[sub] for all sub ⊆ mask
// init dp[mask] = f[mask], then:
void sos(vector<int> &dp, int n) {
for(int i = 0; i < n; i++)
for(int mask = 0; mask < (1 << n); mask++)
if(mask >> i & 1)
dp[mask] += dp[mask ^ (1 << i)];
}
// O(n * 2^n)
Sieve of Eratosthenes
vector<bool> sieve(int n) {
vector<bool> is_prime(n + 1, true);
is_prime[0] = is_prime[1] = false;
for(int i = 2; (long long)i * i <= n; i++)
if(is_prime[i])
for(int j = i * i; j <= n; j += i)
is_prime[j] = false;
return is_prime;
}
// Linear sieve + smallest prime factor (for O(log n) factorization)
int spf[N]; // smallest prime factor
void linearSieve(int n) {
vector<int> primes;
iota(spf, spf + n + 1, 0);
for(int i = 2; i <= n; i++) {
if(spf[i] == i) primes.pb(i); // i is prime
for(int j = 0; j < (int)primes.size() && primes[j] <= spf[i] && (long long)i * primes[j] <= n; j++)
spf[i * primes[j]] = primes[j];
}
}
vector<int> factorize(int x) {
vector<int> f;
while(x > 1) { f.pb(spf[x]); x /= spf[x]; }
return f;
}
GCD / LCM / Extended GCD
long long gcd(long long a, long long b) { return b ? gcd(b, a % b) : a; }
long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }
// Extended GCD: returns gcd, sets x, y such that ax + by = gcd(a, b)
long long extgcd(long long a, long long b, long long &x, long long &y) {
if(!b) { x = 1; y = 0; return a; }
long long x1, y1;
long long g = extgcd(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return g;
}
// modinv via extgcd (works for non-prime mod too):
// long long inv = ((x % mod) + mod) % mod;
Binary Search on Answer
// "minimum value such that check(mid) is true"
// check(mid) must be monotone: false...false...true...true
auto bsearch = [&](long long lo, long long hi) {
while(lo < hi) {
long long mid = lo + (hi - lo) / 2;
if(check(mid)) hi = mid;
else lo = mid + 1;
}
return lo; // first value where check is true
};
// "maximum value such that check(mid) is true"
auto bsearchMax = [&](long long lo, long long hi) {
while(lo < hi) {
long long mid = lo + (hi - lo + 1) / 2;
if(check(mid)) lo = mid;
else hi = mid - 1;
}
return lo;
};
Two Pointers / Sliding Window
// Count subarrays with sum exactly k (non-negative array: use two pointers)
// For general arrays: prefix sum + hashmap
int countSubarraysSum(vector<int> &a, int k) {
unordered_map<int,int> freq;
freq[0] = 1;
int psum = 0, ans = 0;
for(int x : a) {
psum += x;
ans += freq[psum - k];
freq[psum]++;
}
return ans;
}
// Longest subarray with sum <= k (non-negative values)
int longestSubarray(vector<int> &a, int k) {
int l = 0, sum = 0, ans = 0;
for(int r = 0; r < (int)a.size(); r++) {
sum += a[r];
while(sum > k) sum -= a[l++];
ans = max(ans, r - l + 1);
}
return ans;
}
Bit Manipulation Tricks
// Check if bit k is set
bool bitSet(int x, int k) { return (x >> k) & 1; }
// Set bit k
int setBit(int x, int k) { return x | (1 << k); }
// Clear bit k
int clearBit(int x, int k) { return x & ~(1 << k); }
// Lowest set bit
int lsb(int x) { return x & (-x); }
// Count set bits
int popcount(int x) { return __builtin_popcount(x); } // int
int popcount(ll x) { return __builtin_popcountll(x); } // long long
// Enumerate all subsets of mask (including empty)
for(int sub = mask; sub > 0; sub = (sub - 1) & mask) {
// process sub
}
// Add sub == 0 case separately if needed
// Next permutation of bits (same popcount, next larger value)
int nextPerm(int x) {
int c = x & -x, r = x + c;
return (((r ^ x) >> 2) / c) | r;
}
// Check power of 2
bool isPow2(int x) { return x > 0 && !(x & (x - 1)); }
Ordered Set (PBDS — Policy-Based Data Structure)
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>,
rb_tree_tag, tree_order_statistics_node_update> ordered_set;
// ordered_set s;
// s.insert(x);
// s.find_by_order(k) → iterator to k-th element (0-indexed)
// s.order_of_key(x) → number of elements strictly less than x
// For duplicates: use pair<int,int> with unique IDs as second element
Mo’s Algorithm (Offline Range Queries)
struct Query { int l, r, idx; };
// Block size = sqrt(n)
void mo(vector<int> &a, vector<Query> &queries) {
int n = a.size(), q = queries.size();
int block = max(1, (int)sqrt(n));
sort(queries.begin(), queries.end(), [&](auto &a, auto &b) {
int ba = a.l / block, bb = b.l / block;
if(ba != bb) return ba < bb;
return (ba & 1) ? (a.r > b.r) : (a.r < b.r); // alternating for speed
});
vector<int> ans(q);
int curL = 0, curR = -1; // current window
auto add = [&](int pos) { /* add a[pos] to current window */ };
auto rem = [&](int pos) { /* remove a[pos] from current window */ };
for(auto &[l, r, idx] : queries) {
while(curR < r) add(++curR);
while(curL > l) add(--curL);
while(curR > r) rem(curR--);
while(curL < l) rem(curL++);
ans[idx] = /* current answer */;
}
}
// O((n + q) * sqrt(n))
2-SAT
// Variables: 1..n. Literal x = x, negation = x + n.
// Clause (a OR b): add edges ~a -> b and ~b -> a.
struct TwoSat {
int n;
vector<int> g[2*N], rg[2*N];
bool vis[2*N];
vector<int> order;
int comp[2*N];
int numSCC;
void init(int _n) { n = _n; }
int neg(int x) { return x <= n ? x + n : x - n; }
void addClause(int a, int b) { // a OR b
g[neg(a)].pb(b); g[neg(b)].pb(a);
rg[b].pb(neg(a)); rg[a].pb(neg(b));
}
void dfs1(int u) { vis[u]=1; for(auto v:g[u]) if(!vis[v]) dfs1(v); order.pb(u); }
void dfs2(int u, int c) { comp[u]=c; for(auto v:rg[u]) if(comp[v]==-1) dfs2(v,c); }
// returns true if satisfiable, fills vals[]
bool solve(vector<bool> &vals) {
for(int i=1;i<=2*n;i++) if(!vis[i]) dfs1(i);
fill(comp+1, comp+2*n+1, -1);
numSCC = 0;
for(int i=2*n-1;i>=0;i--)
if(comp[order[i]]==-1) dfs2(order[i], numSCC++);
vals.resize(n+1);
for(int i=1;i<=n;i++) {
if(comp[i] == comp[i+n]) return false;
vals[i] = comp[i] > comp[i+n];
}
return true;
}
};
// addClause(a, b): variable a is literal a (true) or a+n (false), same for b
Random Utilities
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int randInt(int l, int r) {
return uniform_int_distribution<int>(l, r)(rng);
}
// Shuffle
shuffle(all(v), rng);
// Random hash base (anti-hack)
const int BASE = uniform_int_distribution<int>(200, 1e9)(rng);
Stress Testing Snippet
// In a separate file or toggle with #define
// brute.cpp and sol.cpp compiled separately
// stress.sh:
// while true; do
// python3 gen.py > inp.txt
// ./brute < inp.txt > out_brute.txt
// ./sol < inp.txt > out_sol.txt
// if ! diff -q out_brute.txt out_sol.txt; then echo "DIFF!"; break; fi
// done
Will add new patterns here as encountered. The rule: never debug a structure twice.