# C++S's CODEBOOK ###### by @XDEv11, @D4nnyLee [TOC] ``` "vimrc if filereadable("/etc/vim/vimrc") source /etc/vim/vimrc endif colo default set bg=dark set cul hi cursorline cterm=bold ctermbg=none ctermfg=none set cuc hi cursorcolumn cterm=bold ctermbg=none ctermfg=none set is set hls hi search cterm=underline ctermbg=none ctermfg=none set nu set cindent set aw set ts=4 set shiftwidth=4 set sts=0 set noet imap <F1> <C-o>ofor (int i{0}; i < ; ++i)<C-o>F; imap <F2> <C-o>ofor (auto& x : )<left> imap jk <ESC> ``` ``` ## makefile CXXFLAGS := -std=c++17 -O2 -Wall -Wextra -Wshadow \ --debug -fsanitize=address,undefined -D_GLIBCXX_DEBUG MAKE_FLAG := --no-print-directory %: INPUT = $(shell echo $@ | tr [:upper:] [:lower:]).in %: EXE = x$@.exe %: @make $(MAKE_FLAG) $(EXE) @make $(MAKE_FLAG) $(INPUT) ./$(EXE) < $(INPUT) x%.exe: %.cpp g++ $(CXXFLAGS) -o $@ $< %.in: vim $@ clean: rm -f *.exe ``` ```bash! #!/usr/bin/env bash CODE=$1.cpp INPUT=`echo $1 | tr [:upper:] [:lower:]`.in EXE=x$1.exe CXXFLAGS='-std=c++17 -O2 -Wall -Wextra -Wshadow --debug -fsanitize=address,undefined -D_GLIBCXX_DEBUG' g++ $CXXFLAGS -o $EXE $CODE if [[ $? -eq 0 ]]; then if [[ ! -e $INPUT ]]; then vim $INPUT fi echo -e 'Executing...\n' ./$EXE < $INPUT fi ``` `#include <bits/stdc++.h>` # Data Structure ### DSU ```cpp! // fast disjoint set union class DSU { vector<int> pa, sz; public: explicit DSU(int n) : pa(n, -1), sz(n, 1) {} int find(int x) { // collapsing find return pa[x] == -1 ? x : pa[x] = find(pa[x]); } void unionn(int x, int y) { // weighted union auto rx{find(x)}, ry{find(y)}; if (rx == ry) return ; if (sz[rx] < sz[ry]) swap(rx, ry); pa[ry] = rx, sz[rx] += sz[ry]; } }; ``` ```cpp! // previous/next one class PvNx { vector<int> pa, sz, mn, mx; int find(int x) { // collapsing find return pa[x] == -1 ? x : pa[x] = find(pa[x]); } void unionn(int x, int y) { // weighted union auto rx{find(x)}, ry{find(y)}; if (rx == ry) return ; if (sz[rx] < sz[ry]) swap(rx, ry); pa[ry] = rx, sz[rx] += sz[ry], mn[rx] = min(mn[rx], mn[ry]), mx[rx] = max(mx[rx], mx[ry]); } public: explicit PvNx(int n) : pa(n + 1, -1), sz(n + 1, 1), mn(n + 1) { iota(mn.begin(), mn.end(), 0), mx = mn; } void remove(int i) { unionn(i, i + 1); } int prev(int i) { return mn[find(i)] - 1; } int next(int i) { int j{mx[find(i)]}; if (i == j) j = mx[find(j + 1)]; return j; } bool exist(int i) { return i == mx[find(i)]; } }; ``` ### Sparse Table ```cpp! // sparse table template<typename value_t, class merge_t> class ST { int n; vector<int> log2; vector<vector<value_t>> t; merge_t merge; // associative & idempotent function for ST public: explicit ST(const vector<value_t>& v, const merge_t& _merge = merge_t{}) : n{v.size()}, log2(n + 1), merge{_merge} { log2[1] = 0; for (int i{2}; i <= n; ++i) log2[i] = log2[i / 2] + 1; t.assign(n, vector<value_t>(log2[n] + 1)); for (int i{n - 1}; i >= 0; --i) { t[i][0] = v[i]; for (int j{1}; i + (1 << j) <= n; ++j) t[i][j] = merge(t[i][j - 1], t[i + (1 << (j - 1))][j - 1]); } } value_t query(int l, int r) { // [l:r) int j{log2[r - l]}; return merge(t[l][j], t[r - (1 << j)][j]); } }; ``` ### Segment Tree > [source](https://codeforces.com/blog/entry/18051) > [proof](https://hackmd.io/@XDEv11/iterative-segment-tree-proof) ```cpp! // segment tree // segment tree template<typename value_t, class merge_t> class SGT { int n; vector<value_t> t; // root starts at 1 value_t defa; merge_t merge; // associative function for SGT public: explicit SGT(int _n, value_t _defa, const merge_t& _merge = merge_t{}) : n{_n}, t(2 * n), defa{_defa}, merge{_merge} {} void modify(int p, const value_t& x) { for (t[p += n] = x; p > 1; p >>= 1) t[p >> 1] = merge(t[p], t[p ^ 1]); } value_t query(int l, int r) { return query(l, r, defa); } value_t query(int l, int r, value_t init) { // [l:r) for (l += n, r += n; l < r; l >>= 1, r >>= 1) { if (l & 1) init = merge(init, t[l++]); if (r & 1) init = merge(init, t[--r]); } return init; } }; ``` ```cpp! class SGT { int n; vector<long long> t; int left(int tv) { return tv + 1; } int right(int tv, int tl, int tm) { return tv + 2 * (tm - tl); } void modify(int p, long long x, int tv, int tl, int tr) { if (tr - tl > 1) { int tm{(tl + tr) / 2}; if (p < tm) modify(p, x, left(tv), tl, tm); else modify(p, x, right(tv, tl, tm), tm, tr); t[tv] = t[left(tv)] + t[right(tv, tl, tm)]; } else t[tv] = x; } long long query(int l, int r, int tv, int tl, int tr) { if (l == tl && r == tr) return t[tv]; int tm{(tl + tr) / 2}; if (r <= tm) return query(l, r, left(tv), tl, tm); else if (l >= tm) return query(l, r, right(tv, tl, tm), tm, tr); else return query(l, tm, left(tv), tl, tm) + query(tm, r, right(tv, tl, tm), tm, tr); } public: explicit SGT(int _n) : n{_n}, t(2 * n - 1) {} void modify(int p, long long x) { modify(p, x, 0, 0, n); }; long long query(int l, int r) { return query(l, r, 0, 0, n); } int ps_lower_bound(long long ps) { // prefix sum lower bound if (ps > t[0]) return n; int tv{0}, tl{0}, tr{n}; while (tr - tl > 1) { int tm{(tl + tr) / 2}; if (t[left(tv)] >= ps) tv = left(tv), tr = tm; else ps -= t[left(tv)], tv = right(tv, tl, tm), tl = tm; } return tl; } }; ``` #### range modification (lazy propagation) ```cpp! // segment tree // range query & range modify template<typename value_t> class SGT { using node_t = pair<value_t, int>; int n; vector<node_t> t; vector<optional<value_t>> lz; // [ tv+1 : tv+2*(tm-tl) ) -> left subtree int left(int tv) { return tv + 1; } int right(int tv, int tl, int tm) { return tv + 2 * (tm - tl); } /** differ from case to case **/ // query is "max" and modify is "add" here node_t merge(const node_t& x, const node_t& y) { // associative function return max(x, y); } void update(int tv, int len, const value_t& x) { if (!lz[tv]) lz[tv] = x; else lz[tv] = lz[tv].value() + x; t[tv].fi = t[tv].fi + x; } /******************************/ void build(const vector<value_t>& v, int tv, int tl, int tr) { if (tr - tl > 1) { int tm{(tl + tr) / 2}; build(v, left(tv), tl, tm); build(v, right(tv, tl, tm), tm, tr); t[tv] = merge(t[left(tv)], t[right(tv, tl, tm)]); } else t[tv] = {v[tl], tl}; } void push(int tv, int tl, int tr) { // lazy propagation if (!lz[tv]) return ; int tm{(tl + tr) / 2}; update(left(tv), tm - tl, lz[tv].value()); update(right(tv, tl, tm), tr - tm, lz[tv].value()); lz[tv].reset(); } void set(int p, const value_t& x, int tv, int tl, int tr) { if (tr - tl > 1) { push(tv, tl, tr); int tm{(tl + tr) / 2}; if (p < tm) set(p, x, left(tv), tl, tm); else set(p, x, right(tv, tl, tm), tm, tr); t[tv] = merge(t[left(tv)], t[right(tv, tl, tm)]); } else t[tv].fi = x; } void rmodify(int l, int r, const value_t& x, int tv, int tl, int tr) { if (!(l == tl && r == tr)) { push(tv, tl, tr); int tm{(tl + tr) / 2}; if (r <= tm) rmodify(l, r, x, left(tv), tl, tm); else if (l >= tm) rmodify(l, r, x, right(tv, tl, tm), tm, tr); else rmodify(l, tm, x, left(tv), tl, tm), rmodify(tm, r, x, right(tv, tl, tm), tm, tr); t[tv] = merge(t[left(tv)], t[right(tv, tl, tm)]); } else update(tv, tr - tl, x); } node_t rquery(int l, int r, int tv, int tl, int tr) { if (l == tl && r == tr) return t[tv]; push(tv, tl, tr); int tm{(tl + tr) / 2}; if (r <= tm) return rquery(l, r, left(tv), tl, tm); else if (l >= tm) return rquery(l, r, right(tv, tl, tm), tm, tr); else return merge(rquery(l, tm, left(tv), tl, tm), rquery(tm, r, right(tv, tl, tm), tm, tr)); } public: explicit SGT(const vector<value_t>& v) : n{v.size()}, t(2 * n - 1), lz(2 * n - 1) { build(v, 0, 0, n); } void set(int p, const value_t& x) { set(p, x, 0, 0, n); } void rmodify(int l, int r, const value_t& x) { rmodify(l, r, x, 0, 0, n); } // [l:r) node_t rquery(int l, int r) { return rquery(l, r, 0, 0, n); } // [l:r) }; ``` ### Time Segment Tree (with Intermittent Event) ```cpp! class DSU { vector<int> pa, sz; stack<pair<int, int>> rec; public: explicit DSU(int n) : pa(n, -1), sz(n, 1), rec{} {} int find(int x) { return pa[x] == -1 ? x : find(pa[x]); } bool unionn(int x, int y) { // weighted union auto rx{find(x)}, ry{find(y)}; if (rx == ry) return false; if (sz[rx] < sz[ry]) swap(rx, ry); pa[ry] = rx, sz[rx] += sz[ry]; rec.emplace(rx, ry); return true; } void undo() { auto [rx, ry]{rec.top()}; rec.pop(); pa[ry] = -1, sz[rx] -= sz[ry]; } }; class EventSGT { int n, m; vector<vector<pair<int, int>>> t; DSU dsu; int left(int tv) { return tv + 1; } int right(int tv, int tl, int tm) { return tv + 2 * (tm - tl); } void add_event(pair<int, int> e, int l, int r, int tv, int tl, int tr) { if (l == tl && r == tr) return t[tv].push_back(e), []{}(); int tm{(tl + tr) / 2}; if (r <= tm) add_event(e, l, r, left(tv), tl, tm); else if (l >= tm) add_event(e, l, r, right(tv, tl, tm), tm, tr); else add_event(e, l, tm, left(tv), tl, tm), add_event(e, tm, r, right(tv, tl, tm), tm, tr); } void run(int tv, int tl, int tr) { int cnt{}; for (auto& [x, y] : t[tv]) cnt += dsu.unionn(x, y); if (tr - tl == 1) { auto& [x, y]{query[tl]}; if (x != -1 && y != -1) ans[tl] = (dsu.find(x) == dsu.find(y)); } else { int tm{(tl + tr) / 2}; run(left(tv), tl, tm), run(right(tv, tl, tm), tm, tr); } while (cnt--) dsu.undo(); } public: vector<pair<int, int>> query; vector<bool> ans; explicit EventSGT(int _n, int _m) : n{_n}, m{_m}, t(2 * n - 1), dsu{m}, query(n, {-1, -1}), ans(n) {} void add_event(pair<int, int> e, int l, int r) { add_event(e, l, r, 0, 0, n); } void add_query(pair<int, int> e, int tm) { query[tm] = e; } void run() { run(0, 0, n); } bool get_ans(int tm) { return ans[tm]; } }; ``` # Algorithm ## Sequence ### LIS ```cpp! // longest increasing subsequence int LIS(const vector<int>& s) { // use binary search to update the smallest element // that ends in a subsequence of length d vector<int> v{}; v.push_back(s[0]); for (int i{1}; i < s.size(); ++i) if (s[i] > v.back()) v.push_back(s[i]); else *lower_bound(v.begin(), v.end(), s[i]) = s[i]; return v.size(); } ``` ### LCS ```cpp! // longest common subsequence int LCS(const vector<int>& a, const vector<int>& b) { vector<vector<int>> dp(a.size() + 1, vector<int>(b.size() + 1)); for (int i{1}; i <= int(a.size()); ++i) for (int j{1}; j <= int(b.size()); ++j) { dp[i][j] = max(dp[i][j], max(dp[i - 1][j], dp[i][j - 1])); if (a[i - 1] == b[j - 1]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1); } return dp[a.size()][b.size()]; } ``` ## Graph ### tree diameter ```cpp! // tree diameter int dfs(int u, int w = -1) { int mx{0}; for (auto& v : adj[u]) if (v != w) { auto len{1 + dfs(v, u)}; diam = max(diam, mx + len); mx = max(mx, len); } return mx; } ``` ```cpp! pair<int, int> dfs(int u, int w = -1) { pair<int, int> mx{0, u}; for (auto& v : adj[u]) if (v != w) { auto [len, leaf]{dfs(v, u)}; mx = max(mx, {len + 1, leaf}); } return mx; } int tree_diameter() { // assume 'b' and 'c' are endpoints of a tree diameter // choose a arbitrary node 'a' // let 'x' be the node that 'a' first meet path "b - c" // 'a' will finally find either 'b' or 'c' through 'x' as its longest path auto b{dfs(0).second}; return dfs(b).first; } ``` ### all longest path ```cpp! // all longest path (generalization of the tree diameter problem) vector<tuple<int, int, int>> dp{}; // [mx1, x, mx2] the path of mx1 goes through x int dfs1(int u, int w = -1) { int mx{0}; for (auto& v : adj[u]) if (v != w) { auto l{1 + dfs1(v, u)}; mx = max(mx, l); auto& [mx1, x, mx2]{dp[u]}; if (l >= mx1) mx2 = mx1, mx1 = l, x = v; else if (l > mx2) mx2 = l; } return mx; } void dfs2(int u, int w = -1) { if (w != -1) { int tmx; { // calculate the longest path through parent auto& [mx1, x, mx2]{dp[w]}; if (x != u) tmx = mx1 + 1; else tmx = mx2 + 1; } { // update the path auto& [mx1, x, mx2]{dp[u]}; if (tmx >= mx1) mx2 = mx1, mx1 = tmx, x = w; else if (tmx > mx2) mx2 = tmx; } } for (auto& v : adj[u]) if (v != w) dfs2(v, u); } void all_longest_path() { dfs1(0), dfs2(0); } ``` ### LCA (TODO) ```cpp! // binary lifting class LCA { const vector<vector<int>>& adj; int n; vector<int> d; vector<int> log2; vector<vector<int>> an{}; void dfs(int u, int w = -1, int dep = 0) { d[u] = dep; an[u][0] = w; for (int i{1}; i <= log2[n - 1] && an[u][i - 1] != -1; ++i) an[u][i] = an[an[u][i - 1]][i - 1]; // 走 2^(i-1) 再走 2^(i-1) 步 // 因為計算 an 會用到祖先的資訊,所以先計算再繼續往下 for (auto& v : adj[u]) { if (v == w) continue; // parent dfs(v, u, dep + 1); } } public: LCA(const vector<vector<int>>& _adj, int root) : adj{_adj}, n{adj.size()}, d(n), log2(n) { log2[1] = 0; for (int i{2}; i < log2.size(); ++i) log2[i] = log2[i / 2] + 1; an.assign(n, vector<int>(log2[n - 1] + 1, -1)); dfs(root); } int operator()(int u, int v) { if (d[u] > d[v]) swap(u, v); for (int i{log2[d[v] - d[u]]}; i >= 0; --i) if (d[v] - d[u] >= (1 << i)) v = an[v][i]; // v 先走到跟 u 同高度 if (u == v) return u; for (int i{log2[d[u]]}; i >= 0; --i) if (an[u][i] != an[v][i]) u = an[u][i], v = an[v][i]; // u, v 一起走到 lca(u, v) 的下方 return an[u][0]; // 回傳 lca(u, v) } }; ``` ```cpp! // Euler Tour Technique class LCA { const vector<vector<int>>& adj; int n; vector<int> d, first, euler{}, log2{}; vector<vector<int>> st{}; void dfs(int u, int w = -1, int dep = 0) { d[u] = dep; first[u] = euler.size(); euler.push_back(u); for (auto& v : adj[u]) { if (v == w) continue; dfs(v, u, dep + 1); euler.push_back(u); } } public: LCA(const vector<vector<int>>& _adj, int root) : adj{_adj}, n{adj.size()}, d(n), first(n) { dfs(root); int tn{euler.size()}; log2.resize(tn + 1); log2[1] = 0; for (int i{2}; i <= tn; ++i) log2[i] = log2[i / 2] + 1; st.assign(tn, vector<int>(log2[tn] + 1)); for (int i{tn - 1}; i >= 0; --i) { st[i][0] = euler[i]; for (int j{1}; i + (1 << j) <= tn; ++j) { auto& x{st[i][j - 1]}; auto& y{st[i + (1 << (j - 1))][j - 1]}; st[i][j] = d[x] <= d[y] ? x : y; } } } int operator()(int u, int v) { int l{first[u]}, r{first[v]}; if (l > r) swap(l, r); ++r; // make the interval left closed right open int j{log2[r - l]}; auto& x{st[l][j]}; auto& y{st[r - (1 << j)][j]}; return d[x] <= d[y] ? x : y; } }; ``` ```cpp! // heavy-light decomposition class LCA { const vector<vector<int>>& adj; int n; vector<int> pa, dep, heavy, head; // 父節點, 深度, 重邊, 路徑起點 int heavy_light(int u, int w = -1, int d = 0) { pa[u] = w, dep[u] = d; int mx{0}, tot{1}; for (auto& v : adj[u]) { if (v == w) continue; int sz{heavy_light(v, u, d + 1)}; if (sz > mx) mx = sz, heavy[u] = v; tot += sz; } return tot; } void decompose(int u, int h) { head[u] = h; for (auto& v : adj[u]) { if (v == pa[u]) continue; if (v == heavy[u]) decompose(v, h); else decompose(v, v); } } public: LCA(const vector<vector<int>>& _adj, int root) : adj{_adj}, n{adj.size()}, pa(n), dep(n), heavy(n), head(n) { // Heavy-Light Decomposition heavy_light(root); decompose(root, root); } int operator()(int u, int v) { while (head[u] != head[v]) { if (dep[head[u]] <= dep[head[v]]) v = pa[head[v]]; else u = pa[head[u]]; } return dep[u] <= dep[v] ? u : v; } }; ``` ### Heavy-light decomposition ```cpp! class HLD { // Heavy-Light Decomposition vector<int> pa, sz, dep, hv, hd; void heavy_light(const vector<vector<int>>& adj, int u, int w = -1, int d = 0) { pa[u] = w, sz[u] = 1, dep[u] = d; int mx{0}; for (auto& v : adj[u]) { if (v == w) continue; heavy_light(adj, v, u, d + 1); sz[u] += sz[v]; if (sz[v] > mx) mx = sz[v], hv[u] = v; } } void decompose(const vector<vector<int>>& adj, int u, int h) { hd[u] = h; for (auto& v : adj[u]) { if (v == pa[u]) continue; if (v == hv[u]) decompose(adj, v, h); else decompose(adj, v, v); } } public: HLD(const vector<vector<int>>& adj, int root) : pa(adj.size()), sz(adj.size()), dep(adj.size()), hv(adj.size(), -1), hd(adj.size()) { heavy_light(adj, root), decompose(adj, root, root); } int parent(int v) { return pa[v]; } int size(int v) { return sz[v]; } int depth(int v) { return dep[v]; } int heavy(int v) { return hv[v]; } int head(int v) { return hd[v]; } }; ``` ### MST ```cpp! // Kruskal’s algorithm vector<tuple<int, int, long long>> Kruskal(int n, vector<tuple<long long, int, int>>& edges) { vector<tuple<int, int, long long>> mst{}; DSU dsu{n}; sort(edges.begin(), edges.end()); for (auto& [w, u, v] : edges) if (dsu.find(u) != dsu.find(v)) dsu.unionn(u, v), mst.emplace_back(u, v, w); return mst; } ``` ```cpp! // Prim's algorithm vector<tuple<int, int, long long>> Prim(const vector<vector<pair<int, long long>>>& adj) { const auto& n{adj.size()}; vector<tuple<int, int, long long>> mst{}; vector<bool> found(n, false); using ti = tuple<long long, int, int>; priority_queue<ti, vector<ti>, greater<ti>> pq{}; found[0] = true; for (auto& [v, w] : adj[0]) pq.emplace(w, 0, v); for (int i{0}; i < n - 1; ++i) { int mn, u, v; do { tie(mn, u, v) = pq.top(), pq.pop(); } while (found[v]); found[v] = true, mst.emplace_back(u, v, mn); for (auto& [x, w] : adj[v]) pq.emplace(w, v, x); } return mst; } ``` ### Articulation point & Bridge & BCC ```cpp! // Hopcroft & Tarjan class graph { vector<int> dep, low; stack<pair<int, int>> s{}; vector<int> bccno; void dfs(int u, int w = -1, int d = 1) { int child{0}; low[u] = dep[u] = d; for (auto& v : adj[u]) { if (v == w || dep[v] >= dep[u]) continue; if (!dep[v]) { // tree edge ++child; s.emplace(u, v); dfs(v, u, d + 1); low[u] = min(low[u], low[v]); if (low[v] >= dep[u]) { ap[u] = true; bcc.emplace_back(); while (true) { auto [x, y]{s.top()}; s.pop(); if (bccno[x] != bcc.size()) bcc.back().push_back(x), bccno[x] = bcc.size(); if (bccno[y] != bcc.size()) bcc.back().push_back(y), bccno[y] = bcc.size(); if (x == u && y == v) break; } } if (low[v] > dep[u]) bridge.emplace_back(u, v); } else low[u] = min(low[u], dep[v]); // back edge } if (w == -1) ap[u] = (child > 1); } public: vector<vector<int>> adj; vector<bool> ap; vector<pair<int, int>> bridge{}; vector<vector<int>> bcc{}; graph(int n) : dep(n, 0), low(n), bccno(n), adj(n), ap(n, false) {} void run() { for (int i{0}; i < adj.size(); ++i) if (!dep[i]) dfs(i); } }; ``` ### SCC ```cpp! // Tarjan’s strongly connected components algorithm class SCC { int d; vector<int> dfn{}, low{}; vector<int> sccno{}; vector<vector<int>> scc{}; stack<int> s{}; void dfs(const vector<vector<int>>& adj, int u) { low[u] = dfn[u] = ++d; s.emplace(u); for (auto& v : adj[u]) { if (sccno[v]) continue; // cross edge if (!dfn[v]) { // tree edge dfs(adj, v); low[u] = min(low[u], low[v]); } else low[u] = min(low[u], dfn[v]); // forward / back / cross edge } if (low[u] == dfn[u]) { // first vertex of a scc scc.emplace_back(); while (true) { int x{s.top()}; s.pop(); sccno[x] = scc.size(), scc.back().push_back(x); if (x == u) break; } } } public: SCC()=default; vector<vector<int>> operator()(const vector<vector<int>>& adj) { int n{adj.size()}; d = 0, dfn.assign(n, 0), low.resize(n), sccno.assign(n, 0); for (int i{0}; i < n; ++i) if (!dfn[i]) dfs(adj, i); return move(scc); } }; ``` :::spoiler Kosaraju's algorithm ```cpp! // scc // Kosaraju's algorithm class graph { vector<vector<int>> rvs; // reverse graph vector<bool> vis; stack<int> s{}; vector<int> component{}; void dfs1(int u) { vis[u] = true; for (auto& v : rvs[u]) if (!vis[v]) dfs1(v); s.push(u); } void dfs2(int u) { vis[u] = true; component.push_back(u); for (auto& v : adj[u]) if (!vis[v]) dfs2(v); } public: vector<vector<int>> adj; vector<int> sccno{}; vector<vector<int>> scc{}; explicit graph(int n) : rvs(n), vis(n), adj(n), sccno(n) {} void add_edge(int u, int v) { adj[u].push_back(v); rvs[v].push_back(u); } void kosaraju() { // find the order on reverse graph for (int u{0}; u < adj.size(); ++u) if (!vis[u]) dfs1(u); // find scc on reverse order fill(vis.begin(), vis.end(), false); while (!s.empty()) { auto u{s.top()}; s.pop(); if (!vis[u]) { dfs2(u); scc.push_back(move(component)); for (auto& v : scc.back()) sccno[v] = scc.size(); } } } }; ``` ::: ### Topological sort ```cpp! // topological sort 1 optional<vector<int>> top_sort(vector<vector<int>>& adj) { vector<int> res{}; int n{static_cast<int>(adj.size())}; vector<int> cnt(n, 0); // predecessor count for (int u{0}; u < n; ++u) for (auto& v : adj[u]) ++cnt[v]; queue<int> qu{}; for (int u{0}; u < n; ++u) if (!cnt[u]) qu.push(u); while (!qu.empty()) { auto u{qu.front()}; qu.pop(); res.push_back(u); for (auto& v : adj[u]) if (!--cnt[v]) qu.push(v); } if (res.size() != adj.size()) return nullopt; return res; } ``` ```cpp! // topological sort 2 class DAG { public: int n; vector<vector<int>> adj; vector<int> s, order{}; explicit DAG(int n) : n{n}, adj(n), s(n) {} bool dfs(int u) { // state 0 : unvisited, state 1 : processing, state 2 : finished s[u] = 1; for (auto& v : adj[u]) if (s[v] == 1 || (s[v] == 0 && !dfs(v))) return false; // cycle order.push_back(u); s[u] = 2; return true; } bool topSort() { for (int i{0}; i < n; ++i) if (s[i] == 0 && !dfs(i)) return order.clear(), false; reverse(order.begin(), order.end()); return true; } }; ``` ### 2-SAT ```cpp! auto scc{SCC{}(adj)}; vector<int> sccid(2 * n); for (int i{0}; i < scc.size(); ++i) { for (auto& v : scc[i]) sccid[v] = i; } for (int i{0}; i < n; ++i) { if (sccid[2 * i] == sccid[2 * i + 1]) return cout << "-1\n", true; } vector<vector<int>> sccadj(scc.size()); for (int i{0}; i < scc.size(); ++i) for (auto& u : scc[i]) for (auto& v : adj[u]) { if (sccid[v] == i) continue; sccadj[i].push_back(sccid[v]); } for (auto& v : sccadj) { sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); } vector<int> ans(n, -1); auto ts{top_sort(sccadj)}; for (auto& i : ts.value()) for (auto& v : scc[i]) { if (ans[v / 2] != -1) continue; ans[v / 2] = v & 1; } ``` :::spoiler old ```cpp! class twoSat { int n; vector<vector<int>> adj; stack<int> s{}; bool dfs(int x) { if (mark[x ^ 1]) return false; if (mark[x]) return true; mark[x] = true; s.push(x); for (auto& y : adj[x]) if (!dfs(y)) return false; return true; } public: vector<bool> mark; twoSat(int _n) : n{_n}, adj(2 * n), mark(2 * n, false) {} void or_clause(int x, bool xv, int y, bool yv) { // ((x == xv) || (y == yv)) x = 2 * x + xv, y = 2 * y + yv; adj[x ^ 1].push_back(y); adj[y ^ 1].push_back(x); } void xor_clause(int x, bool xv, int y, bool yv) { // ((x == xv) xor (y == yv)) x = 2 * x + xv, y = 2 * y + yv; adj[x].push_back(y ^ 1), adj[x ^ 1].push_back(y); adj[y].push_back(x ^ 1), adj[y ^ 1].push_back(x); } bool solve() { for (int i{0}; i < n; ++i) { if (mark[2 * i] || mark[2 * i + 1]) continue; while (!s.empty()) s.pop(); if (!dfs(2 * i)) { while (!s.empty()) mark[s.top()] = false, s.pop(); if (!dfs(2 * i + 1)) return false; } } return true; } }; ``` ::: ### Eulerian cycle (TODO) ```cpp! vector<int> euler_cycle(vector<vector<pair<int, int>>>& adj, int w = 0) { int n{adj.size()}, m{}; for (int v{0}; v < n; ++v) m += adj[v].size(); m /= 2; vector<int> res{}; stack<int> stk{}; stk.push(w); vector<int> nxt(n); vector<bool> usd(m); while (!stk.empty()) { auto u{stk.top()}; while (nxt[u] < adj[u].size() && usd[adj[u][nxt[u]].se]) ++nxt[u]; if (nxt[u] < adj[u].size()) { auto [v, i]{adj[u][nxt[u]]}; ++nxt[u], usd[i] = true, stk.push(v); } else res.push_back(u), stk.pop(); } return res; } ``` ### Shortest Path ```cpp! // Bellman-Ford algorithm template<typename T> optional<vector<optional<T>>> Bellman_Ford(const vector<vector<pair<int, T>>>& adj, int s) { const auto& n{adj.size()}; vector<optional<T>> d(n, nullopt); d[s] = 0; queue<int> qu{}, qu2{}; vector<bool> in(n, false), in2(n, false); qu.push(s), in[s] = true; for (int i{0}; i < n; ++i) { // at most n-1 edges while (!qu.empty()) { int u{qu.front()}; qu.pop(), in[u] = false; for (auto& [v, w] : adj[u]) if (!d[v] || d[v] > d[u].value() + w) { // relax d[v] = d[u].value() + w; if (!in2[v]) qu2.push(v), in2[v] = true; } } qu.swap(qu2), in.swap(in2); } if (qu.empty()) return d; return nullopt; // if negative cycle } ``` ```cpp! // Dijkstra algorithm template<typename T> vector<optional<T>> Dijkstra(const vector<vector<pair<int, T>>>& adj, int s) { const auto& n{adj.size()}; vector<optional<T>> d(n, nullopt); d[s] = 0; vector<bool> found(n, false); using pq_t = pair<T, int>; priority_queue<pq_t, vector<pq_t>, greater<pq_t>> pq{}; pq.emplace(0, s); while (!pq.empty()) { auto [_, u]{pq.top()}; pq.pop(); if (found[u]) continue; found[u] = true; for (auto& [v, w] : adj[u]) if (!d[v] || d[v] > d[u].value() + w) { d[v] = d[u].value() + w; pq.emplace(d[v].value(), v); } } return d; } ``` ```cpp! // Floyd-Warshall algorithm template<typename T> vector<vector<optional<T>>> Floyd_Warshall(const vector<vector<optional<T>>>& adj) { const auto& n{adj.size()}; auto d{adj}; for (int i{0}; i < n; ++i) d[i][i] = 0; for (int k{0}; k < n; ++k) for (int i{0}; i < n; ++i) for (int j{0}; j < n; ++j) { if (!d[i][k] || !d[k][j]) continue; // no value if (!d[i][j] || d[i][j] > d[i][k].value() + d[k][j].value()) d[i][j] = d[i][k].value() + d[k][j].value(); } return d; } ``` ### Matching #### maximum cardinality bipartite matching ```cpp! class BipartiteMatching { vector<bool> vis; vector<int> mx{}, my{}; bool dfs(const vector<vector<int>>& adj, int x) { for (auto& y : adj[x]) { if (vis[y]) continue; vis[y] = true; if (my[y] == -1 || dfs(adj, my[y])) { mx[x] = y, my[y] = x; return true; } } return false; } public: pair<vector<int>, vector<int>> operator()(const vector<vector<int>>& adj, int ny) { vis.resize(ny), mx.assign(adj.size(), -1), my.assign(ny, -1); int c{0}; for (int x{0}; x < adj.size(); ++x) { fill(vis.begin(), vis.end(), false); if (dfs(adj, x)) ++c; } return {move(mx), move(my)}; } }; ``` ```cpp! // maximum cardinality bipartite matching // Hopcroft–Karp algorithm - O(E√V) class bipartiteGraph { int nx, ny; vector<int> dx, dy; bool dfs(int y) { for (auto& x : adjy[y]) { if (dx[x] + 1 != dy[y]) continue; if (mx[x] == -1 || dfs(mx[x])) { my[y] = x, mx[x] = y; dy[y] = -1; // augmented - remove from BFS forest return true; } } dy[y] = -1; // no augmenting path - remove from BFS forest return false; } bool bfs() { fill(dx.begin(), dx.end(), -1); fill(dy.begin(), dy.end(), -1); queue<int> qu{}, qu2{}; for (int x{0}; x < nx; ++x) // use all unmatched x's as roots if (mx[x] == -1) qu.push(x), dx[x] = 0; bool found{false}; while (!qu.empty() && !found) { // stop at the level found while (!qu.empty()) { auto x{qu.front()}; qu.pop(); for (auto& y : adjx[x]) if (dy[y] == -1 && my[y] != x) { dy[y] = dx[x] + 1; if (my[y] == -1) found = true; else qu2.push(my[y]), dx[my[y]] = dy[y] + 1; } } qu.swap(qu2); } return found; } vector<vector<int>> adjx, adjy; public: vector<int> mx, my; bipartiteGraph(int _nx, int _ny) : nx{_nx}, ny{_ny}, dx(nx), dy(ny) , adjx(nx), adjy(ny), mx(nx, -1), my(ny, -1) {} void addEdge(int x, int y) { adjx[x].push_back(y), adjy[y].push_back(x); } int Hopcroft_Karp() { int c{0}; while (bfs()) { for (int y{0}; y < ny; ++y) if (my[y] == -1 && dy[y] != -1) c += dfs(y); } return c; } }; ``` #### maximum weight bipartite matching ```cpp! // Hungarian Algorithm - O(V^3) class bipartiteGraph { int n; vector<long long> lx, ly; vector<bool> vx, vy; queue<int> qu{}; // only X's vertices vector<int> py; vector<long long> dy; // smallest (lx[x] + ly[y] - w[x][y]) vector<int> pdy; // & which x void relax(int x) { for (int y{0}; y < n; ++y) if (lx[x] + ly[y] - w[x][y] < dy[y]) dy[y] = lx[x] + ly[y] - w[x][y], pdy[y] = x; } void augment(int y) { while (y != -1) { int x{py[y]}, yy{mx[x]}; mx[x] = y, my[y] = x; y = yy; } } bool bfs() { while (!qu.empty()) { int x{qu.front()}; qu.pop(); for (int y{0}; y < n; ++y) { if (!vy[y] && lx[x] + ly[y] == w[x][y]) { vy[y] = true, py[y] = x; if (my[y] == -1) return augment(y), true; int xx{my[y]}; qu.push(x), vx[xx] = true, relax(xx); } } } return false; } void relabel() { long long d{numeric_limits<long long>::max()}; for (int y{0}; y < n; ++y) if (!vy[y]) d = min(d, dy[y]); for (int x{0}; x < n; ++x) if (vx[x]) lx[x] -= d; for (int y{0}; y < n; ++y) if (vy[y]) ly[y] += d; for (int y{0}; y < n; ++y) if (!vy[y]) dy[y] -= d; } bool expand() { // expand one layer with new equality edges for (int y{0}; y < n; ++y) { if (!vy[y] && dy[y] == 0) { vy[y] = true, py[y] = pdy[y]; if (my[y] == -1) return augment(y), true; int xx{my[y]}; qu.push(xx), vx[xx] = true, relax(xx); } } return false; } public: vector<vector<long long>> w; vector<int> mx, my; bipartiteGraph(int _n) : n{_n}, lx(n), ly(n), vx(n), vy(n), py(n), dy(n), pdy(n), w(n, vector<long long>(n, 0)), mx(n, -1), my(n, -1) {} long long Hungarian() { for (int i{0}; i < n; ++i) { lx[i] = ly[i] = 0; for (int j{0}; j < n; ++j) lx[i] = max(lx[i], w[i][j]); mx[i] = my[i] = -1; } for (int x{0}; x < n; ++x) { fill(vx.begin(), vx.end(), false); fill(vy.begin(), vy.end(), false); fill(dy.begin(), dy.end(), numeric_limits<long long>::max()); qu = {}, qu.push(x), vx[x] = true, relax(x); while (!bfs()) { relabel(); if (expand()) break; } } long long weight{0}; for (int x{0}; x < n; ++x) weight += w[x][mx[x]]; return weight; } }; ``` #### maximum cardinality matching ```cpp! // maximum cardinality matching // Micali-Vazirani algorithm // todo ``` ```cpp! // maximum matching // Edmonds' Blossom algorithm // O(VEα(E,V)) class graph { int n; vector<int> p, d, a, c1, c2; // (alternating tree), (unvisited: -1, even: 0, odd: 1), (auxiliary for lca), (cross edge) int label{0}; /* DSU */ vector<int> dsu_p, dsu_sz, dsu_b; void dsu_reset() { fill(dsu_p.begin(), dsu_p.end(), -1); fill(dsu_sz.begin(), dsu_sz.end(), 1); iota(dsu_b.begin(), dsu_b.end(), 0); } int find(int x) { // collapsing find return dsu_p[x] == -1 ? x : dsu_p[x] = find(dsu_p[x]); } int base(int x) { return dsu_b[find(x)]; } void contract(int x, int y) { // weighted union auto rx{find(x)}, ry{find(y)}; if (rx == ry) return ; auto b{dsu_b[rx]}; // treat x's base as new base if (dsu_sz[rx] < dsu_sz[ry]) swap(rx, ry); dsu_p[ry] = rx, dsu_sz[rx] += dsu_sz[ry], dsu_b[rx] = b; } /*******/ queue<int> qu{}; // only even vertices void handle_one_side(int x, int y, int b) { for (int v{base(x)}; v != b; v = base(p[v])) { c1[v] = x, c2[v] = y, contract(b, v); if (d[v] == 1) qu.push(v); // odd vertex -> even vertex } } int lca(int u, int v) { ++label; // use next number in order not to clear a while (true) { if (a[u] == label) return u; a[u] = label; if (p[u] != -1) u = base(p[u]); swap(u, v); } } void augment(int r, int y) { if (r == y) return ; if (d[y] == 0) { // even vertex -> odd vertex // check d[y] == 0 instead of d[p[y]] == 1, so (m[y], y) is in the blossom augment(m[y], m[c1[y]]); augment(r, m[c2[y]]); m[c1[y]] = c2[y], m[c2[y]] = c1[y]; } else { int x{p[y]}; augment(r, m[x]); m[x] = y, m[y] = x; } } bool bfs(int r) { dsu_reset(); fill(d.begin(), d.end(), -1); qu = {}, qu.push(r), d[r] = 0; while (!qu.empty()) { int x{qu.front()}; qu.pop(); for (auto& y : adj[x]) { if (base(x) == base(y)) continue; if (d[y] == -1) { p[y] = x, d[y] = 1; if (m[y] == -1) { // augmenting path augment(-1, y); return true; } else { p[m[y]] = y, d[m[y]] = 0; qu.push(m[y]); } } else if (d[base(y)] == 0) { // blossom int b{lca(base(x), base(y))}; handle_one_side(x, y, b); handle_one_side(y, x, b); } } } return false; } public: vector<vector<int>> adj; vector<int> m; explicit graph(int _n) : n{_n}, p(n, -1), d(n), a(n), c1(n), c2(n), dsu_p(n), dsu_sz(n), dsu_b(n), adj(n), m(n, -1) {} int Edmonds() { int c{0}; for (int v{0}; v < n; ++v) if (m[v] == -1 && bfs(v)) ++c; return c; } }; ``` #### maximum weight matching (TODO) ```cpp! // maximum weight matching // Edmonds' Blossom algorithm ``` #### stable matching ```cpp! // Stable Marriage Problem (stable matching) // Gale–Shapley algorithm class bipartiteGraph { public: int n; vector<vector<int>> px, py; vector<int> mx, my; bipartiteGraph(int _n) : n(_n), px(n, vector<int>(n)), py(n, vector<int>(n)), mx(n, -1), my(n, -1) {} void Gale_Shapley() { queue<int> qu{}; vector<priority_queue<pair<int, int>>> pq(n); for (int x{0}; x < n; ++x) { qu.push(x); for (int y{0}; y < n; ++y) pq[x].emplace(px[x][y], y); } while (!qu.empty()) { auto x{qu.front()}; qu.pop(); int y; do { y = pq[x].top().second; pq[x].pop(); } while (my[y] != -1 && py[y][x] <= py[y][my[y]]); if (my[y] != -1) mx[my[y]] = -1, qu.push(my[y]); // y prefers x to my[y] mx[x] = y, my[y] = x; } } }; ``` ### Flow #### maximum flow ```cpp! // minimum cut maximum flow // relabel-to-front algorithm // (an implemention of generic push-relabel algorithm) // handle the capacity, c, of a vertex, v. // Add a new vertex, v', and an edge v-v' with capacity c. template<typename T> //requires signed_integral<T> void handle_vertex_capacity(int u, T c, int& n, vector<tuple<int, int, T>>& e) { int w{n++}; for (auto& [_u, _v, _c] : e) if (_u == u) _u = w; e.emplace_back(u, w, c); } template<typename T> //requires signed_integral<T> class flowNetwork { int n, s, t; vector<int> h; // height label vector<T> e; // excess vector<vector<int>> adj; // adjacent list vector<vector<T>> c, r{}; vector<size_t> p; // record the position processed list<int> lst{}; // topological sort of admissible network void push(int u, int v) { T f{min(e[u], r[u][v])}; r[u][v] -= f, r[v][u] += f; e[u] -= f, e[v] += f; } void relabel(int u) { int mn{numeric_limits<int>::max()}; for (auto& v : adj[u]) if (r[u][v]) mn = min(mn, h[v]); h[u] = mn + 1; } void init() { fill(h.begin(), h.end(), 0); fill(e.begin(), e.end(), 0); lst.clear(); for (int u{0}; u < n; ++u) if (u != s && u != t) lst.push_back(u); fill(p.begin(), p.end(), 0); r = c; } void preflow() { h[s] = n; for (auto& v : adj[s]) { e[v] += r[s][v], e[s] -= r[s][v]; r[v][s] += r[s][v], r[s][v] = 0; } } bool discharge(int u) { bool flag{false}; while (e[u]) { for (; p[u] < adj[u].size(); ++p[u]) { int v{adj[u][p[u]]}; if (r[u][v] && h[u] == h[v] + 1) push(u, v); if (!e[u]) break; } if (e[u]) relabel(u), p[u] = 0, flag = true; } return flag; // return if relabel or not } public: flowNetwork(int _n) : n{_n}, s{0}, t{n - 1}, h(n), e(n), adj(n), c(n, vector<T>(n)), p(n) {} void set_st(int _s, int _t) { s = _s, t = _t; } void add_edge(int u, int v, T _c) { if (!c[u][v] && !c[v][u]) adj[u].push_back(v), adj[v].push_back(u); c[u][v] += _c; } T max_flow() { assert(s != t); init(); preflow(); auto it{lst.begin()}; while (it != lst.end()) { if (discharge(*it)) { // relabel-to-front lst.push_front(*it), lst.erase(it); it = lst.begin(); } it = next(it); } return e[t]; }; }; ``` ## String ### prefix function (LPS) ```cpp! // longest prefix which is also suffix template<typename T> vector<int> prefix_func(const vector<T>& v) { vector<int> len(v.size()); for (int i{1}; i < v.size(); ++i) { int j{len[i - 1]}; while (j > 0 && v[i] != v[j]) j = len[j - 1]; len[i] = j + (v[i] == v[j]); } return len; } ``` #### Count occurrences of prefix ```cpp! vector<int> cnt(n + 1); cnt[n] = 1; for (int i{0}; i < n; ++i) ++cnt[lps[i]]; for (int i{n}; i >= 1; --i) cnt[lps[i - 1]] += cnt[i]; ``` ### KMP ```cpp! template<typename T> vector<int> KMP(const vector<T> &s, const vector<T> &p) { vector<int> lps{prefix_func(p)}, v{}; for (int i{0}, j{0}; i < s.size(); ++i) { while (j > 0 && s[i] != p[j]) j = lps[j - 1]; if (s[i] == p[j] && ++j == p.size()) v.push_back(i), j = lps[j - 1]; } return v; } ``` #### Building automaton ```cpp! vector<array<int, 26>> fsm(p.size() + 1); fsm[0][p[0] - 'a'] = 1; for (int j{1}; j <= p.size(); ++j) for (int c{0}; c < 26; ++c) { if (j < m && p[j] == 'a' + c) fsm[j][c] = j + 1; else fsm[j][c] = fsm[lps[j - 1]][c]; } ``` ### Z function ```cpp! template<typename T> vector<int> z_func(const vector<T>& v) { int n{v.size()}; vector<int> z(n); int l{0}, r{0}; for(int i{1}; i < n; i++) { if(i < r) z[i] = min(z[i - l], r - i); while (i + z[i] < n && v[z[i]] == v[i + z[i]]) ++z[i]; if (r < i + z[i]) l = i, r = i + z[i]; } return z; } ``` #### Count occurrences of prefix ```cpp! z[0] = n; vector<int> cnt(n + 1); for (int i{0}; i < n; ++i) ++cnt[z[i]]; for (int i{n - 1}; i >= 0; --i) cnt[i] += cnt[i + 1]; ``` ### Suffix Array ```cpp! template<typename T> vector<int> suffix_array(const vector<T>& _v, T s = T{}) { int n{_v.size()}; vector<pair<T, int>> v(n); for (int i{0}; i < n; ++i) v[i] = {_v[i], i}; v.emplace_back(s, n++); sort(v.begin(), v.end()); vector<int> c(n), p(n); c[v[0].se] = 0; for (int i{1}; i < n; ++i) c[v[i].se] = c[v[i - 1].se] + (v[i - 1].fi < v[i].fi); for (int i{0}; i < n; ++i) p[i] = v[i].se; for (int k{0}; (1 << k) < n; ++k) { vector<int> t(n); for (int i{0}; i < n; ++i) t[i] = (p[i] - (1 << k) + n) % n; vector<int> cnt(n, 0); for (int i{0}; i < n; ++i) ++cnt[c[t[i]]]; for (int i{1}; i < n; ++i) cnt[i] += cnt[i - 1]; for (int i{n - 1}; i >= 0; --i) p[--cnt[c[t[i]]]] = t[i]; vector<int> nc(n); nc[p[0]] = 0; for (int i{1}; i < n; ++i) { nc[p[i]] = nc[p[i - 1]] + (c[p[i - 1]] < c[p[i]] || c[(p[i - 1] + (1 << k)) % n] < c[(p[i] + (1 << k)) % n]); } c.swap(nc); } return p.erase(p.begin()), p; } ``` ### LCP array ```cpp! // longest common prefix of consecutive suffixes template<typename T> vector<int> lcp_array(const vector<T>& v, const vector<int>& p) { int n{v.size()}; vector<int> r(n); for (int i{0}; i < n; ++i) r[p[i]] = i; vector<int> lcp(n - 1, 0); for (int i{0}, k{0}; i < n; ++i, k = k ? k - 1 : 0) { if (r[i] == n - 1) continue; // k should be 0 int j{p[r[i] + 1]}; while (i + k < n && j + k < n && v[i + k] == v[j + k]) ++k; lcp[r[i]] = k; } return lcp; } ``` ### Aho–Corasick algorithm ```cpp! template<size_t k = 26> class AC_automaton { struct vertex_t { int pa; bool exit{false}; int tag; array<int, k> next{}, go; int slink, elink, ecnt; explicit vertex_t(int _pa = 0) : pa{_pa} { } }; vector<vertex_t> t; public: explicit AC_automaton(const vector<pair<vector<int>, int>>& dict) : t(1) { for (auto& [s, x] : dict) { int v{0}; for (auto& c : s) { if (!t[v].next[c]) { t[v].next[c] = t.size(); t.emplace_back(v); } v = t[v].next[c]; } if (v) t[v].exit = true, t[v].tag = x; } queue<int> qu{}; qu.push(0), t[0].slink = 0; for (size_t c{0}; c < k; ++c) t[0].go[c] = 0; t[0].elink = 0, t[0].ecnt = 0; while (!qu.empty()) { auto u{qu.front()}; qu.pop(); if (u) { int w{t[u].slink}; for (size_t c{0}; c < k; ++c) t[u].go[c] = (t[w].next[c] ? t[w].next[c] : t[w].go[c]); t[u].elink = (t[w].exit ? w : t[w].elink), t[u].ecnt = t[w].ecnt + t[w].exit; } for (size_t c{0}; c < k; ++c) { auto v{t[u].next[c]}; if (v) qu.push(v), t[v].slink = t[u].go[c]; } } } size_t size() const { return t.size(); } bool exit(int v) const { return t[v].exit; } int tag(int v) const { return t[v].tag; } int next(int v, int c) const { return t[v].next[c]; } int go(int v, int c) const { return t[v].go[c]; } int slink(int v) const { return t[v].slink; } int elink(int v) const { return t[v].elink; } int ecnt(int v) const { return t[v].ecnt; } }; ``` ### Manacher's algorithm ```cpp! template<typename T> pair<vector<int>, vector<int>> Manacher(const vector<T>& _v, T s = T{}) { int n{_v.size()}; vector<T> v(2 * n + 1, s); for (int i{0}; i < n; ++i) v[2 * i + 1] = _v[i]; vector<int> r(2 * n + 1, 1); int c{0}, b{1}; for (int i{1}; i < 2 * n; ++i) { if (i < b) r[i] = min(b - i, r[c - (i - c)]); while (i - r[i] >= 0 && i + r[i] < 2 * n + 1 && v[i - r[i]] == v[i + r[i]]) ++r[i]; if (i + r[i] > b) c = i, b = i + r[i]; } vector<int> ro{}, re{}; for (int i{1}; i <= 2 * n - 1; i += 2) ro.push_back(r[i] - 1); for (int i{2}; i <= 2 * n - 2; i += 2) re.push_back(r[i] - 1); return {ro, re}; } ``` ### SAM (Suffix Automaton) ```cpp! class SAM { struct vertex_t { int len, fp, link; bool cloned; map<int, int> next{}; explicit vertex_t(int l, int f, int lk = -1, bool c = false, const map<int, int>& n = {}) : len{l}, fp{f}, link{lk}, cloned(c), next{n} {} }; vector<vertex_t> st{vertex_t{0, 0}}; int lst{0}; public: explicit SAM() {} void add_back(int ch) { int cur{st.size()}; st.emplace_back(st[lst].len + 1, st[lst].len); int p{lst}; while (p != -1 && !st[p].next.count(ch)) st[p].next[ch] = cur, p = st[p].link; if (p != -1) { int q{st[p].next[ch]}; if (st[p].len + 1 != st[q].len) { int c{st.size()}; st.emplace_back(st[p].len + 1, st[q].fp, st[q].link, true, st[q].next); while (p != -1 && st[p].next[ch] == q) st[p].next[ch] = c, p = st[p].link; st[q].link = st[cur].link = c; } else st[cur].link = q; } else st[cur].link = 0; lst = cur; } size_t size() const { return st.size(); } int last() const { return lst; } int len(int v) const { return st[v].len; } int fp(int v) const { return st[v].fp; } int link(int v) const { return st[v].link; } int cloned(int v) const { return st[v].cloned; } const map<int, int>& next(int v) const { return st[v].next; } int next(int v, int ch) const { auto it{st[v].next.find(ch)}; return it == st[v].next.end() ? -1 : it->second; } }; ``` #### Number of different substrings ```cpp! long long c{}; for(int i{1}; i < sam.size(); i++) c += sam.len(i) - sam.len(sam.link(i)); ``` #### Number of occurrences ```cpp! vector<pair<int, int>> tmp(sam.size()); for (int v{0}; v < sam.size(); ++v) tmp[v] = {sam.len(v), v}; sort(tmp.rbegin(), tmp.rend()); vector<long long> cnt(sam.size()); for (int v{0}; v < sam.size(); ++v) { if (!sam.cloned(v)) cnt[v] = 1; } for (auto& [len, v] : tmp) { if (v) cnt[sam.link(v)] += cnt[v]; } ``` # Math ## General ### Integer Square Root ```cpp! unsigned long long Intsqrt(unsigned long long x) { unsigned long long l{0ULL}, r{1ULL << 32}; while (r - l > 1) { auto m{(l + r) / 2}; if (m * m <= x) l = m; else r = m; } return l; } ``` ### Combination ```cpp! ll Cnm(ll n, ll m) { if (m > n / 2) m = n - m; ll r{1}; for (ll i{1}, j{n}; i <= m; ++i, --j) r *= j, r /= i; return r; } ``` ### Mint ```cpp! using ll = long long; const ll PM{1000000007}; ll MN(ll a) { return (a % PM + PM) % PM; } ll MA(ll a, ll b) { return (a + b) % PM; } ll MS(ll a, ll b) { return (a - b + PM) % PM; } ll MM(ll a, ll b) { return (a * b) % PM; } ll MP(ll a, ll b) { ll res{1}; do { if (b & 1) res = MM(res, a); } while (a = MM(a, a), b >>= 1); return res; } ll MI(ll a) { return MP(a, PM - 2); } ll MD(ll a, ll b) { return MM(a, MI(b)); } ``` :::spoiler class version ```cpp! class mint { long long n{0}; public: constexpr static long long mod{set value first}; mint()=default; mint(long long _n) : n{(_n % mod + mod) % mod} {} mint(const mint&)=default; mint& operator=(const mint&)=default; operator long long() { return n; } mint& operator+=(const mint &x) { n = (n + x.n) % mod; return *this; } mint& operator*=(const mint &x) { n = (n * x.n) % mod; return *this; } mint& operator-=(const mint &x) { return (*this) += mod - x.n; } }; template<class L, class R> enable_if_t<(is_integral_v<L> || is_same_v<L, mint>) && (is_integral_v<R> || is_same_v<R, mint>), mint> operator+(const L& lhs, const R& rhs) { return mint{lhs} += mint{rhs}; } template<class L, class R> enable_if_t<(is_integral_v<L> || is_same_v<L, mint>) && (is_integral_v<R> || is_same_v<R, mint>), mint> operator-(const L& lhs, const R& rhs) { return mint{lhs} -= mint{rhs}; } template<class L, class R> enable_if_t<(is_integral_v<L> || is_same_v<L, mint>) && (is_integral_v<R> || is_same_v<R, mint>), mint> operator*(const L& lhs, const R& rhs) { return mint{lhs} *= mint{rhs}; } ``` ::: ### Euler's totient function ```cpp! int euler_phi(int n) { int res{n}; for (int i{2}; i * i <= n; ++i) { if (n % i) continue; while (n % i == 0) n /= i; res = res / i * (i - 1); } if (n > 1) res = res / n * (n - 1); return res; } ``` ```cpp! constexpr int maxn{100000}; vector<int> phi{[] { vector<int> v(maxn + 1); v[1] = 1; for (int i{2}; i <= maxn; ++i) { if (v[i]) continue; v[i] = i; for (int j{i}; j <= maxn; j += i) { if (!v[j]) v[j] = j; v[j] = v[j] / i * (i - 1); } } return v; }()}; ``` ### Extended Euclidean Algorithm :::spoiler original version > [Explanation](https://hackmd.io/Whu1Q5dcSNuMMHXLwM5yzg) ```cpp! // Extended Eculidean Algorithm // solve Linear Diophantine Equation template<typename T> pair<T, T> operator- (const pair<T, T>& x, const pair<T, T>& y) { return {x.first - y.first, x.second - y.second}; } template<typename T> pair<T, T> operator* (const T& k, const pair<T, T>& p) { return {k * p.first, k * p.second}; } template<typename T> pair<T, T> extEuc(T x, T y) { pair<T, T> p{1, 0}, q{0, 1}; if (x < y) swap(x, y), swap(p, q); // let x >= y while (y) { auto n{p - (x / y) * q}; auto r{x % y}; x = y, p = q; y = r, q = n; } return p; } ``` ::: ```cpp! /* solve x, y for ax + by = gcd(a, b) = g */ template<typename T> void extEcu(T a, T b, T &g, T &x, T &y) { if (b) extEcu(b, a % b, g, y, x), y -= x * (a / b); else g = a, x = 1, y = 0; } ``` ### Fast Power ```cpp! /* Iterative Function to calculate (a^b) % mod in O(log b) */ long long power_mod(long long a, long long b, long long mod) { long long res{1}; while (b > 0) { if (b & 1) res = res * a % mod; b >>= 1; a = (a * a) % mod; } return res; } ``` ### Modular Multiplicative Inverse ```cpp! /* exists when a and mod are coprime */ long long MI(long long a, long long mod) { return power_mod(a, euler_phi(mod) - 1, mod); } ``` ```cpp! long long MI(long long a, long long mod) { long long d, x, y; extEcu(a, mod, d, x, y); return d == 1 ? (x + mod) % mod : -1; } ``` ### Chinese Remainder Theorem ```cpp! // coprime (p^k) pair<ll, ll> CRT(const vector<pair<ll, ll>>& congruences) { ll M{1}, sol{}; for (auto& [m, a] : congruences) M *= m; for (auto& [m, a] : congruences) { ll x{M / m}, y{MI(x, m)}; sol = MA(sol, MM(MM(a, x, M), y, M), M); } return {M, sol}; } ``` ### Floyd's cycle-finding algorithm ```cpp! template<class value_t, class func_t> pair<size_t, size_t> FloydsTortoiseAndHare(value_t x0, func_t func) { value_t t{x0}, h{x0}; do { t = func(t), h = func(func(h)); } while (t != h); size_t mu{0}; t = x0; while (t != h) t = func(t), h = func(h), ++mu; size_t lam{0}; do { h = func(h), ++lam; } while (t != h); return {mu, lam}; } ``` ## Computational Geometry ```cpp! struct Point { double x, y; Point(double _x = 0, double _y = 0) : x{_x}, y{_y} {} }; using Vector = Point; Vector operator+(const Vector &v1, const Vector &v2) { return {v1.x + v2.x, v1.y + v2.y}; } Vector operator-(const Vector &v1, const Vector &v2) { return {v1.x - v2.x, v1.y - v2.y}; } Vector operator*(const Vector &v, double d) { return {v.x * d, v.y * d}; } Vector operator/(const Vector &v, double d) { return {v.x / d, v.y / d}; } bool operator<(const Point &p1, const Point &p2) { if (p1.x != p2.x) return p1.x < p2.x; return p1.y < p2.y; } int dcmp(double x) { if (fabs(x) < 1e-12) return 0; return x > 0 ? 1 : -1; } bool operator==(const Point &p1, const Point &p2) { return dcmp(p1.x - p2.x) == 0 && dcmp(p1.y - p2.y) == 0; } ``` ### Basic ```cpp! double dot(const Vector &v1, const Vector &v2) { return v1.x * v2.x + v1.y * v2.y; } double length(const Vector &v) { return sqrt(dot(v, v)); } double cross(const Vector &v1, const Vector &v2) { return v1.x * v2.y - v1.y * v2.x; } double angle(const Vector &v1, const Vector &v2) { return acos(dot(v1, v2) / length(v1) / length(v2)); } // 2 * area of the triangle {p1, p2, p3} double area2(const Point &p1, const Point &p2, const Point &p3) { return cross(p2 - p1, p3 - p1); } Vector rotate(const Vector &v, double rad) { return {v.x * cos(rad) - v.y * sin(rad), v.x * sin(rad) + v.y * cos(rad)}; } ``` ### Intersection of Two Lines ```cpp! // get the intersection of 2 lines below: // 1. p + t1 * v // 2. q + t2 * u Point LineIntersection(const Point &p, const Vector &v, const Point &q, const Vector &u) { Vector w = q - p; double t1 = cross(u, w) / cross(u, v); return p + v * t1; } ``` ### Distance to Line ```cpp! double DistanceToLine(const Point &p, const Point &a, const Point &b) { return abs(cross(p - a, b - a) / length(b - a)); } double DistanceToSegment(const Point &p, const Point &a, const Point &b) { Vector v1 = p - a, v2 = b - a, v3 = p - b; if (a == b) return length(v1); if (dot(v1, v2) < 0) return length(v1); if (dot(v2, v3) > 0) return length(v3); return DistanceToLine(p, a, b); } ``` ### Projection ```cpp! Point Projecttion(const Point &p, const Point &a, const Point &b) { Vector v = b - a; return a + v * (dot(v, p - a) / dot(v, v)); } ``` ### Segment Intersect ```cpp! template<typename T> pair<T, T> operator-(const pair<T, T>& lhs, const pair<T, T>& rhs) { auto& [lf, ls]{lhs}; auto& [rf, rs]{rhs}; return {lf - rf, ls - rs}; } template<typename T> int rotation(const pair<T, T>& o, const pair<T, T>& p1, const pair<T, T>& p2) { auto v1{p1 - o}, v2{p2 - o}; // 1 for CW, -1 for CCW, and 0 for parallel auto& [x1, y1]{v1}; auto& [x2, y2]{v2}; auto cp{x1 * y2 - x2 * y1}; // cross product return cp ? cp / abs(cp) : 0; } template<typename T> bool intersect(pair<pair<T, T>, pair<T, T>> s1, pair<pair<T, T>, pair<T, T>> s2) { auto& [p1, p2]{s1}; auto& [p3, p4]{s2}; auto r1{rotation(p1, p2, p3)}; auto r2{rotation(p1, p2, p4)}; auto r3{rotation(p3, p4, p1)}; auto r4{rotation(p3, p4, p2)}; // assume p is on line e1-e2, check if p is on segment e1-e2 auto on_segment = [](const pair<T, T>& e1, const pair<T, T>& e2, const pair<T, T>& p) { auto& [x1, y1]{e1}; auto& [x2, y2]{e2}; auto& [x, y]{p}; return min(x1, x2) <= x && x <= max(x1, x2) && min(y1, y2) <= y && y <= max(y1, y2); }; if ((r1 && r1 == -1 * r2) && (r3 && r3 == -1 * r4)) return true; else if (r1 == 0 && on_segment(p1, p2, p3)) return true; else if (r2 == 0 && on_segment(p1, p2, p4)) return true; else if (r3 == 0 && on_segment(p3, p4, p1)) return true; else if (r4 == 0 && on_segment(p3, p4, p2)) return true; return false; } ``` ### Polygon Area ```cpp! double PolygonArea(const vector<Point> &p) { int n{p.size()}; double area{0}; for (int i{2}; i < n; ++i) area += cross(p[i - 1] - p[0], p[i] - p[0]); return fabs(area / 2); } ``` ### Circles ```cpp! struct Circle { Point c; double r; Point getPoint(double a) const { return {c.x + cos(a) * r, c.y + sin(a) * r}; } }; int GetLineCircleIntersection(const Point& p, const Vector& v, const Circle& c, double& t1, double& t2, vector<Point>& sol) { double c1{v.x}, c2{p.x - c.c.x}, c3{v.y}, c4{p.y - c.c.y}; double c5{c1 * c1 + c3 * c3}, c6{2 * (c1 * c2 + c3 * c4)}, c7{c2 * c2 + c4 * c4 - c.r * c.r}; double delta{c6 * c6 - 4 * c5 * c7}; if (dcmp(delta, 0) < 0) return 0; if (dcmp(delta, 0) == 0) { t1 = t2 = -c6 / (2 * c5), sol.push_back(p + v * t1); return 1; } t1 = (-c6 - sqrt(delta)) / (2 * c5), sol.push_back(p + v * t1); t2 = (-c6 + sqrt(delta)) / (2 * c5), sol.push_back(p + v * t2); return 2; } int GetCircleIntersection(const Circle& c1, const Circle& c2, vector<Point>& sol) { double d{Length(c1.c - c2.c)}; if (dcmp(d, 0) == 0) { if (dcmp(c1.r, c2.r) == 0) return -1; return 0; } if (dcmp(c1.r + c2.r, d) < 0) return 0; if (dcmp(abs(c1.r - c2.r), d) > 0) return 0; double a{Angle(c1.c - c2.c)}; double da{acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d))}; Point p1{c1.getPoint(a - da)}, p2{c1.getPoint(a + da)}; sol.push_back(p1); if (p1 == p2) return 1; sol.push_back(p2); return 2; } int getTangents(const Point& p, const Circle& c, vector<Vector>& sol) { Vector u{c.c - p}; double d{Length(u)}; if (dcmp(d, c.r) > 0) return 0; else if (dcmp(d, c.r) == 0) { sol.push_back(Rotate(u, PI / 2)); return 1; } } ``` ## Game Theory :::info sg value: **mex** of successive states nim value: **xor-sum** of all independent games' sg values ::: ## Formula ### Power Summation ```cpp! // 1 + 4 + ... + n^2 n * (n + 1) * (2 * n + 1) / 6 ``` ```cpp! // 4 + 16 + ... + (2n)^2 (2 * n) * (n + 1) * (2 * n + 1) / 3 ``` ```cpp! // 1 + 9 + ... + (2n+1)^2 n * (2 * n - 1) * (2 * n + 1) / 3 ``` ```cpp! // 1 + 8 + ... + n^3 (n^4 + 2 * n^3 + n^2) / 4 ``` ```cpp! // 1 + 16 + ... + n^4 (6 * n^5 + 15 * n^4 + 10 * n^3 - n) / 30 ``` ```cpp! // 1 + 32 + ... + n^5 (2 * n^6 + 6 * n^5 + 5 * n^4 - n^2) / 12 ``` ```cpp! // 1 + 64 + ... + n^6 (6 * n^7 + 21 * n^6 + 21 * n^5 - 7 * n^3 + n) / 42 ``` ```cpp! // 1 + 128 + ... + n^7 (3 * n^8 + 12 * n^7 + 14 * n^6 - 7 * n^4 + 2 * n^2) / 24 ``` ```cpp! // 1 + + ... + n^8 (10 * n^9 + 45 * n^8 + 60 * n^7 - 42 * n^5 + 20 * n^3 - 3 * n) / 90 ``` ```cpp! // 1 + + ... + n^9 (2 * n^10 + 10 * n^9 + 15 * n^8 - 14 * n^6 + 10 * n^4 - 3 * n^2) / 20 ``` ```cpp! // 1 + + ... + n^10 (6 * n^11 + 33 * n^10 + 55 * n^9 - 66 * n^7 + 66 * n^5 - 33 * n^3 + 5 * n) / 66 ``` ### Summation of Combination ```cpp // Odd term // k = 1 - n % 2 // C(1, n) + C(3, n) + ... + C(n - k, n) = 2^(n - 1) ``` # Resources ## Online Judge * [CSES](https://cses.fi/problemset/list/) * [UVa](https://onlinejudge.org/index.php) * [程式自學平台](https://e-tutor.itsa.org.tw/e-Tutor/Question_bank.php?id=30) ## Reference * [Competitive Programmer’s Handbook](https://cses.fi/book/book.pdf?fbclid=IwAR0Gru8WZO9AnOIAiPXuL9Kdk-s__QuYvSfsfgPMfjtkFLznItnyIe91wuE) * [演算法筆記](http://web.ntnu.edu.tw/~algo/) * [CP-Algorithms](https://cp-algorithms.com/) * [koosaga's github](https://github.com/koosaga/olympiad/tree/master/Library) ### C++ * [cppreference](https://en.cppreference.com/w/) * [cplusplus](http://www.cplusplus.com/) ###### tags: `cp`