--- title: Template (C++) tags: Programming Contest --- # Graph ## Dijkstra ```cpp template <typename T> struct Dijkstra { vector<T> dis; vector<int> par; Dijkstra(int n, T inf) { dis = vector<T>(n, inf); par = vector<int>(n, -1); } void run(const vector<vector<pair<int, T>>> &adj, const vector<int> &sources) { using Item = pair<T, int>; priority_queue<Item, vector<Item>, greater<Item>> que; for (auto u : sources) { dis[u] = 0; par[u] = u; que.push({dis[u], u}); } while (!que.empty()) { auto [d, u] = que.top(); que.pop(); if (d > dis[u]) { continue; } for (auto [v, w] : adj[u]) { auto new_d = dis[u] + w; if (new_d < dis[v]) { dis[v] = new_d; par[v] = u; que.push({dis[v], v}); } } } } }; ``` https://cses.fi/problemset/result/6059594/ ## SegTree ```cpp #include <algorithm> #include <iostream> #include <vector> #include <functional> using namespace std; template <typename S, typename F> struct LazySegTree { // lazy[u] != default_lazy <-> data[lch] and data[rch] are not up-to-date, // but data[u] is. lazy[u] == default_lazy <-> data[u], data[lch], data[rch] // are up-to-date. int NN; vector<S> data; vector<F> lazy; virtual S default_data() = 0; virtual F default_lazy() = 0; virtual S op(S a, S b) = 0; virtual S apply_lazy(F lazy, S val, int u, int l, int r) = 0; virtual F merge_lazy(F parent, F child) = 0; LazySegTree() = default; // Calling virtual functions in constructor is not allowed. // Therefore, we use this function instead. void build_from_vector(const vector<S> &A) { this->NN = 1; while (this->NN < int(A.size())) { this->NN <<= 1; } this->data = vector<S>(2 * this->NN, this->default_data()); this->lazy = vector<F>(2 * this->NN, this->default_lazy()); for (int i = 0; i < int(A.size()); i++) { this->data[this->NN - 1 + i] = A[i]; } for (int u = this->NN - 2; u >= 0; u--) { this->data[u] = this->op(this->data[u * 2 + 1], this->data[u * 2 + 2]); } } // Apply lazy[u] to lch and rch, so data[lch] and data[rch] are updated. // Merge lazy[u] into lazy[lch] and lazy[rch] void push(int u, int l, int r) { if (lazy[u] == this->default_lazy()) return; int m = (l + r) / 2; int lch = u * 2 + 1; int rch = u * 2 + 2; this->data[lch] = this->apply_lazy(this->lazy[u], this->data[lch], lch, l, m); this->data[rch] = this->apply_lazy(this->lazy[u], this->data[rch], rch, m, r); this->lazy[lch] = this->merge_lazy(this->lazy[u], this->lazy[lch]); this->lazy[rch] = this->merge_lazy(this->lazy[u], this->lazy[rch]); this->lazy[u] = this->default_lazy(); } S prod(int a, int b, int u = -1, int l = -1, int r = -1) { if (u == -1) u = 0, l = 0, r = this->NN; if (l >= b || r <= a) return this->default_data(); if (l >= a && r <= b) return this->data[u]; int m = (l + r) / 2; this->push(u, l, r); S res1 = this->prod(a, b, u * 2 + 1, l, m); S res2 = this->prod(a, b, u * 2 + 2, m, r); return this->op(res1, res2); } void apply(int a, int b, F x, int u = -1, int l = -1, int r = -1) { if (u == -1) u = 0, l = 0, r = this->NN; if (l >= b || r <= a) return; if (l >= a && r <= b) { this->data[u] = this->apply_lazy(x, this->data[u], u, l, r); this->lazy[u] = this->merge_lazy(x, this->lazy[u]); return; } int m = (l + r) / 2; this->push(u, l, r); this->apply(a, b, x, u * 2 + 1, l, m); this->apply(a, b, x, u * 2 + 2, m, r); this->data[u] = this->op(this->data[u * 2 + 1], this->data[u * 2 + 2]); } int find_first_of(const function<bool(S, int, int, int)> &f, int u = -1, int l = -1, int r = -1) { if (u == -1) u = 0, l = 0, r = this->NN; if (!f(this->data[u], u, l, r)) return -1; if (r - l == 1) return u - (this->NN - 1); int m = (l + r) / 2; int idx1 = this->find_first_of(f, u * 2 + 1, l, m); if (idx1 != -1) return idx1; int idx2 = this->find_first_of(f, u * 2 + 2, m, r); if (idx2 != -1) return idx2; return -1; } }; using S = int; using F = int; struct SegTree : LazySegTree<S, F> { S default_data() { return 0x3f3f3f3f; } F default_lazy() { return 0; } S op(S lch, S rch) { return min(lch, rch); } S apply_lazy(F lazy, S val, int u, int l, int r) { return lazy + val; } F merge_lazy(F parent, F child) { return parent + child; } }; ``` 驗題: * https://atcoder.jp/contests/abc223/submissions/33287093 * https://judge.yosupo.jp/submission/104918 ## Tree Diamter https://hackmd.io/9KrxOEwRRA6LYrfn1NA9pQ?view#Tree-Diameter ```cpp tuple<vector<int>, vector<int>, vector<int>> bfs(const vector<vector<int>> &G, int root, int parent) { int N = G.size(); auto vis = vector<int>(); auto par = vector(N, -1); auto dep = vector(N, -1); auto que = queue<tuple<int, int>>(); par[root] = parent; dep[root] = 0; que.push({root, parent}); while (que.size() > 0) { auto [u, p] = que.front(); que.pop(); vis.push_back(u); for (auto v : G[u]) { if (v != p) { par[v] = u; dep[v] = dep[u] + 1; que.push({v, u}); } } } return {vis, par, dep}; } int main() { auto [vis, par, dep] = bfs(G, 0, -1); int s = vis.back(); auto [s_vis, s_par, s_dep] = bfs(G, s, -1); int t = s_vis.back(); return 0; } ``` ## Prefix ```cpp template <typename T> struct Prefix2D { vector<vector<T>> pref; Prefix2D() = default; Prefix2D(const vector<vector<T>> &A) { int N = A.size(); int M = A[0].size(); pref = vector(N, vector<T>(M, 0)); pref[0][0] = A[0][0]; for (int r = 1; r < N; r++) { pref[r][0] = pref[r - 1][0] + A[r][0]; } for (int c = 1; c < M; c++) { pref[0][c] = pref[0][c - 1] + A[0][c]; } for (int r = 1; r < N; r++) { for (int c = 1; c < M; c++) { pref[r][c] = pref[r][c - 1] + pref[r - 1][c] - pref[r - 1][c - 1] + A[r][c]; } } } // [r1, r2] x [c1, c2] T query(int r1, int r2, int c1, int c2) { T ans = pref[r2][c2]; if (r1 >= 1) ans -= pref[r1 - 1][c2]; if (c1 >= 1) ans -= pref[r2][c1 - 1]; if (r1 >= 1 && c1 >= 1) ans += pref[r1 - 1][c1 - 1]; return ans; } }; ``` ## BIT ```cpp template <typename T> struct BIT { vector<T> data; BIT(int n) { data = vector<T>(n, 0); } void add(int idx, T val) { for (int i = idx + 1; i <= data.size() - 1; i += (i & (-i))) { data[i] = data[i] + val; } } T prefix(int idx) { T res = 0; for (int i = idx + 1; i > 0; i -= (i & -i)) { res = res + data[i]; } return res; } T sum(int l, int r) { // l..r T val = prefix(r - 1); if (l != 0) { val -= prefix(l - 1); } return val; } }; ``` https://atcoder.jp/contests/abc294/submissions/39908415 ## Utility ### Argsort ```cpp template <typename T> vector<int> argsort(const vector<T> &v) { vector<pair<T, int>> data; for (int i = 0; i < int(v.size()); i++) { data.push_back({v[i], i}); } sort(data.begin(), data.end()); vector<int> indices; for (auto &&[_, i] : data) { indices.push_back(i); } return indices; } ``` ### Print Vector ```cpp template <typename T> string join(const vector<T> &arr, const string &seperator = " ") { ostringstream oss; for (size_t i = 0; i < arr.size(); i++) { if (i != 0) { oss << seperator; } oss << arr[i]; } return oss.str(); } ``` ### Print Map ```cpp template <typename K, typename V> ostream &operator<<(ostream &out, const map<K, V>& m) { out << "{ "; for (auto &[k, v] : m) { out << k << ": " << v << ", "; } out << "}"; return out; } ``` ### Print Tuple ```cpp template <typename TupType, size_t... I> ostream &tuple_print(ostream &out, const TupType &_tup, index_sequence<I...>) { out << "("; (..., (out << (I == 0 ? "" : ", ") << get<I>(_tup))); out << ")"; return out; } template <typename... T> ostream &operator<<(ostream &out, const tuple<T...> &t) { return tuple_print(out, t, make_index_sequence<sizeof...(T)>()); } ``` ### Print Pair ```cpp template <typename T1, typename T2> ostream &operator<<(ostream &out, const pair<T1, T2>& p) { out << "( " << p.first << ", " << p.second << " )"; return out; } ``` ## Numbers ### Euclidean Division ```cpp pair<ll, ll> euclid_div(ll a, ll b) { ll q = a / b; ll r = a % b; if (r < 0) { r += b; q -= 1; } return {q, r}; } ``` ### GCD ```cpp ll gcd(ll a, ll b) { // gcd(x, 0) = x // gcd(a, b) = gcd(b, r) while (b != 0) { ll r = a % b; a = b; b = r; } return a; } ``` ### ExtGCD ```cpp tuple<ll, ll, ll> extgcd(ll a, ll b) { if (b == 0) { return {1, 0, a}; } else { auto [x1, y1, g] = extgcd(b, (a % b + b) % b); return {y1, x1 - a / b * y1, g}; } } ``` ### Sieve Of Eratosthenes ```cpp using ll = long long; using pll = pair<ll, ll>; struct SieveOfEratosthenes { vector<bool> is_prime; vector<ll> primes; SieveOfEratosthenes(ll V) { is_prime = vector<bool>(V + 1, true); primes = vector<ll>(); for (ll i = 2; i <= V; i ++) { if (is_prime[i]) { primes.push_back(i); for (ll j = i * i; j <= V; j += i) { is_prime[j] = false; } } } } vector<pll> factorize(ll x) { if (x <= 1) { throw invalid_argument("x shoule be > 1"); } auto result = vector<pll>(); for (auto p : primes) { ll exp = 0; while (x % p == 0) { exp++; x = x / p; } if (exp > 0) { result.push_back(pll(p, exp)); } if (p * p > x) { break; } } if (x > 1) { result.push_back(pll(x, 1)); } return result; } }; ``` ## Combination ```cpp template <typename T> struct CombTool { vector<T> fact; vector<T> finv; CombTool(int V) { fact = vector<T>(V, 1); finv = vector<T>(V, 1); for (int i = 1; i < V; i++) { fact[i] = fact[i - 1] * i; } finv[V - 1] = fact.back().inv(); for (int i = V - 2; i >= 0; i--) { finv[i] = finv[i + 1] * (i + 1); } } T comb(int a, int b) { return fact[a] * finv[b] * finv[a - b]; } T perm(int a, int b) { return fact[a] * finv[a - b]; } T hcomb(int a, int b) { return comb(a + b - 1, b); } }; ``` ## Heavy Light Decomposition ```cpp struct HLD { vector<int> size; vector<int> depth; vector<int> heavy; vector<int> parent; vector<int> top; vector<int> tour; vector<int> t_enter; vector<int> t_leave; HLD(const vector<vector<int>> &adj, int root) { int N = adj.size(); const int inf = 0x3f3f3f3f; // Find size, depth, heavy, parent by DFS { size = vector<int>(N, 1); depth = vector<int>(N, 0); heavy = vector<int>(N, inf); parent = vector<int>(N, inf); auto stack = vector<pair<char, int>>{{'l', root}, {'e', root}}; depth[root] = 0; parent[root] = root; while (!stack.empty()) { auto [cmd, u] = stack.back(); stack.pop_back(); if (cmd == 'l') { size[u] = 1; heavy[u] = inf; for (auto v : adj[u]) { if (v != parent[u]) { size[u] += size[v]; if (heavy[u] == inf || size[v] > size[heavy[u]]) { heavy[u] = v; } } } } else { for (auto v : adj[u]) { if (parent[v] == inf) { parent[v] = u; depth[v] = depth[u] + 1; stack.push_back({'l', v}); stack.push_back({'e', v}); } } } } } // Find top, tour, t_enter, t_leave by DFS { int time = 0; top = vector<int>(N, inf); tour = vector<int>(N, inf); t_enter = vector<int>(N, inf); t_leave = vector<int>(N, inf); auto stack = vector<pair<char, int>>{{'l', root}, {'e', root}}; top[root] = root; while (!stack.empty()) { auto [cmd, u] = stack.back(); stack.pop_back(); if (cmd == 'l') { t_leave[u] = time; } else { t_enter[u] = time; tour[time] = u; time++; for (auto v : adj[u]) { if (v != parent[u]) { // heavy edge / light edge top[v] = ((v == heavy[u]) ? top[u] : v); stack.push_back({'l', v}); stack.push_back({'e', v}); } } } } } } int lca(int u, int v) { while (top[u] != top[v]) { if (depth[top[u]] > depth[top[v]]) { u = parent[top[u]]; } else { v = parent[top[v]]; } } return ((depth[u] < depth[v]) ? u : v); } }; ``` https://atcoder.jp/contests/abc294/submissions/39908415 ## Z algorithm https://cp-algorithms.com/string/z-function.html ```cpp vector<int> zfunc(const string& S) { int N = S.length(); vector<int> z(N, 0); int l = 0, r = 0; for (int i = 1; i < N; i++) { if (i <= r) { z[i] = min(r - i, z[i - l]); } while (i + z[i] < N && S[i + z[i]] == S[z[i]]) { z[i]++; } if (i + z[i] - 1 >= r) { l = i; r = i + z[i] - 1; } } return z; } ``` ## Rolling Hash https://cp-algorithms.com/string/string-hashing.html ```cpp #include <cassert> using ll = long long; ll powmod(ll a, ll b, ll m) { ll base = a; ll res = 1; while (b) { if (b & 1) { res = res * base % m; } base = base * base % m; b >>= 1; } return res; } struct PolyHash { ll mod; ll base; vector<ll> powr; vector<ll> pinv; // N is max length; mod should be prime PolyHash(int N, ll base = 31, ll mod = 1e9 + 7) { this->base = base; this->mod = mod; powr = vector<ll>(N, 1); pinv = vector<ll>(N, 1); for (int i = 1; i < N; i++) { powr[i] = powr[i - 1] * base % mod; } pinv[N - 1] = powmod(powr[N - 1], mod - 2, mod); for (int i = N - 2; i >= 0; i--) { pinv[i] = pinv[i + 1] * base % mod; } } vector<ll> transform(const vector<int> &v) { for (auto && x : v) { assert (x != 0); } vector<ll> h(v.size()); h[0] = v[0] % mod; for (size_t i = 1; i < v.size(); i++) { h[i] = (h[i - 1] + v[i] * powr[i] % mod) % mod; } return h; } ll substr(const vector<ll> &h, int l, int r) { // [l, r) if (l == 0) { return h[r - 1]; } else { return ((h[r - 1] - h[l - 1] + mod) % mod) * pinv[l] % mod; } } }; vector<int> string2vector(const string &s) { vector<int> v(s.length()); for (size_t i = 0; i < s.length(); i++) { if (s[i] >= 'a' && s[i] <= 'z') { v[i] = s[i] - 'a' + 1; } else { v[i] = s[i] - 'A' + 1; } } return v; } ```