├── .gitignore ├── lib ├── hash.wasm └── hash.typ ├── img └── utfsm_cp.png ├── content ├── maths │ ├── mulmod.cpp │ ├── binary-pow-mulmod.cpp │ ├── extended-gcd.cpp │ ├── fast-prime-factorization.cpp │ ├── binary-pow.cpp │ ├── euler-phi.cpp │ ├── prime-factors.cpp │ ├── mobius-sieve.cpp │ ├── binary-pow-128-bits.cpp │ ├── euler-phi-sieve.cpp │ ├── pollard-rho.cpp │ ├── factorial.cpp │ ├── erathostenes-sieve.cpp │ ├── counting-divisors.cpp │ ├── tetration.cpp │ ├── poly-shift.cpp │ ├── fraction.cpp │ ├── crt.cpp │ ├── sieveking-kung.cpp │ ├── discrete-log.cpp │ ├── non-deterministic-miller-rabin.cpp │ ├── miller-rabin.cpp │ ├── montgomery.cpp │ ├── divisors.cpp │ ├── lagrange-point.cpp │ ├── xor-basis.cpp │ ├── gauss.cpp │ ├── fwht.cpp │ ├── matrix.cpp │ ├── ntt.cpp │ ├── simplex.cpp │ ├── fast-ntt.cpp │ └── fft.cpp ├── general │ ├── hash.typ │ ├── template.cpp │ └── troubleshoot.typ ├── graphs │ ├── dfs.cpp │ ├── bfs.cpp │ ├── dijkstra.cpp │ ├── floyd-warshall.cpp │ ├── mfed.cpp │ ├── bridges.cpp │ ├── chromatic-number.cpp │ ├── kruskal.cpp │ ├── articulation-points.cpp │ ├── lca-rmq.cpp │ ├── 4-cycle.cpp │ ├── bellman-ford.cpp │ ├── 3-cycle.cpp │ ├── hungarian.cpp │ ├── lca.cpp │ ├── dinic.cpp │ ├── euler-directed-graph.cpp │ ├── centroid-decomposition.cpp │ ├── min-cost-flow.cpp │ ├── eppstein.cpp │ ├── kosaraju.cpp │ ├── hld.cpp │ ├── hopcroft-karp.cpp │ ├── dominator-tree.cpp │ └── ahld.cpp ├── data-structures │ ├── ordered-set.cpp │ ├── union-find.cpp │ ├── min-stack.cpp │ ├── bit.cpp │ ├── bit-2d.cpp │ ├── segment-tree-with-walk.cpp │ ├── min-queue.cpp │ ├── succinct-indexable-dictionary.cpp │ ├── sparse-table.cpp │ ├── merge-sort-tree.cpp │ ├── segment-tree.cpp │ ├── union-find-rollback.cpp │ ├── sqrt-decomposition.cpp │ ├── min-deque.cpp │ ├── disjoint-sparse-table.cpp │ ├── query-tree.cpp │ ├── line-container.cpp │ ├── persistent-segment-tree.cpp │ ├── range-query-constant.cpp │ ├── dynamic-segment-tree.cpp │ ├── bit-vector.cpp │ ├── iterative-segment-tree-lazy.cpp │ ├── extended-segment-tree.cpp │ ├── segment-tree-lazy.cpp │ ├── wavelet-tree.cpp │ ├── lct.cpp │ ├── kd-tree.cpp │ ├── treap.cpp │ └── implicit-treap.cpp ├── geometry │ ├── order-by-slope.cpp │ ├── polygon-area.cpp │ ├── order-by-angle.cpp │ ├── halfplane.cpp │ ├── lattice-point.cpp │ ├── point-inside-polygon.cpp │ ├── segment.cpp │ ├── convex-hull.cpp │ ├── halfplane-intersection.cpp │ ├── point-2d.cpp │ └── nearest-2-points.cpp ├── algorithms │ ├── tortoise-hare.cpp │ ├── mo.cpp │ ├── mo-update.cpp │ └── mo-rollback.cpp ├── strings │ ├── min-rotation.cpp │ ├── rolling-hashing.cpp │ ├── k-rolling-hashing.cpp │ ├── z.cpp │ ├── manacher.cpp │ ├── trie.cpp │ ├── suffix-automaton.cpp │ ├── kmp.cpp │ ├── suffix-array.cpp │ └── aho-corasick.cpp ├── dynamic-programming │ ├── knuth.cpp │ ├── egg-drop.cpp │ ├── d&c.cpp │ ├── lis.cpp │ ├── convex-hull-trick.cpp │ ├── li-chao-tree.cpp │ ├── line-container.cpp │ └── li-chao-segment.cpp └── combinatorial │ ├── simulated-annealing.cpp │ └── weighted-matroid-intersection.cpp ├── main.typ ├── .github └── workflows │ ├── check-tracker.yml │ ├── test-compile.yml │ └── release-new-version.yml ├── LICENSE ├── scripts └── check-tracker.py ├── README.md ├── tracker.yaml └── content.typ /.gitignore: -------------------------------------------------------------------------------- 1 | main.pdf -------------------------------------------------------------------------------- /lib/hash.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProgramacionCompetitivaUTFSM/Handbook-USM/HEAD/lib/hash.wasm -------------------------------------------------------------------------------- /img/utfsm_cp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ProgramacionCompetitivaUTFSM/Handbook-USM/HEAD/img/utfsm_cp.png -------------------------------------------------------------------------------- /content/maths/mulmod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Multiply two number fast, secure for number lesser than $2^57$ 3 | *Status:* Partially tested 4 | */ 5 | ll mulmod(ll a, ll b, ll m) { 6 | ll r=a*b-(ll)((ld)a*b/m+.5)*m; 7 | return r<0?r+m:r; 8 | } 9 | -------------------------------------------------------------------------------- /content/general/hash.typ: -------------------------------------------------------------------------------- 1 | If you want to check if your code is copied correctly, you can check the square at the top right of each code. If it matches the hash of this command, it is correctly copied. 2 | 3 | ```sh 4 | cat template.cpp | tr -d '[:space:]' | md5sum | head -c 6 5 | ``` -------------------------------------------------------------------------------- /content/graphs/dfs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Just traverse a graph in dfs order 3 | *Status:* Tested 4 | */ 5 | void dfs(int s) { 6 | if (visited[s]) return; 7 | visited[s] = true; 8 | // process node s 9 | for (auto u: adj[s]) { 10 | dfs(u); 11 | } 12 | } -------------------------------------------------------------------------------- /content/maths/binary-pow-mulmod.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Binary pow using mulmod, mulmod can be changed. 3 | *Status:* Partially tested 4 | */ 5 | ll binpow(ll b, ll e, ll m){ 6 | if(!e)return 1; 7 | ll q=binpow(b,e/2,m);q=mulmod(q,q,m); 8 | return e&1?mulmod(b,q,m):q; 9 | } 10 | -------------------------------------------------------------------------------- /content/maths/extended-gcd.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Extended euclidean algorithm 3 | *Status:* Not stress-tested, but it gave AC in problems 4 | */ 5 | struct GCD_type { ll x, y, d; }; 6 | GCD_type ex_GCD(ll a, ll b){ 7 | if (b == 0) return {1, 0, a}; 8 | GCD_type pom = ex_GCD(b, a % b); 9 | return {pom.y, pom.x - a / b * pom.y, pom.d}; 10 | } -------------------------------------------------------------------------------- /content/maths/fast-prime-factorization.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Factorize the number using Pollard's Rho and Miller Rabin $O(n^(1/3))$ 3 | *Status:* Partially tested 4 | */ 5 | void fact(ll n, map &f) { //O (lg n)^3 6 | if(n==1) return; 7 | if(nd_miller_rabin(n)) { f[n]++; return; } 8 | ll q=pollard_rho(n); fact(q,f); fact(n/q,f); 9 | } 10 | -------------------------------------------------------------------------------- /content/data-structures/ordered-set.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Built-in version of C++ of select and rank operations in sets 3 | *Status:* Tested 4 | */ 5 | #include 6 | #include 7 | using namespace __gnu_pbds; 8 | template using oset = tree, rb_tree_tag, tree_order_statistics_node_update>; 9 | -------------------------------------------------------------------------------- /content/maths/binary-pow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Exponentiation by squares, computes $a^b mod m$ in $O(log b)$ 3 | *Status:* Highly tested 4 | */ 5 | ll binpow(ll a, ll b, ll m) { 6 | a %= m; 7 | ll res = 1; 8 | while (b > 0) { 9 | if (b & 1) 10 | res = (res * a) % m; 11 | a = (a * a) % m; 12 | b >>= 1; 13 | } 14 | return res; 15 | } -------------------------------------------------------------------------------- /content/geometry/order-by-slope.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Sort the points depending the angle 3 | *Status:* Not tested 4 | */ 5 | template 6 | void orderBySlope(vector> &P) { 7 | sort(P.begin(), P.end(), [](const Point2D &p1, const Point2D &p2) { 8 | Fraction r1 = Fraction(p1.x, p1.y), r2 = Fraction(p2.x, p2.y); 9 | return r2 < r1; 10 | }); 11 | } -------------------------------------------------------------------------------- /content/maths/euler-phi.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Return $phi(n)$, runs on $O(sqrt(n))$ 3 | *Status:* Not tested 4 | */ 5 | ll phi(ll n) { 6 | ll result = n; 7 | for (ll i = 2; i*i <= n; i++) { 8 | if (n % i == 0) { 9 | while (n % i == 0) n /= i; 10 | result -= result / i; 11 | } 12 | } 13 | if (n > 1) 14 | result -= result / n; 15 | return result; 16 | } 17 | -------------------------------------------------------------------------------- /content/maths/prime-factors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get all prime factors of $n$, runs on $O(sqrt(n))$ 3 | *Status:* Highly tested 4 | */ 5 | vector primeFactors(ll n) { 6 | vector factors; 7 | for (ll i = 2; (i*i) <= n; i++) { 8 | while (n % i == 0) { 9 | factors.push_back(i); 10 | n /= i; 11 | } 12 | } 13 | if (n > 1) factors.push_back(n); 14 | return factors; 15 | } -------------------------------------------------------------------------------- /content/graphs/bfs.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Just traverse a graph in bfs order 3 | *Status:* Tested 4 | */ 5 | visited[x] = true; 6 | distance[x] = 0; 7 | q.push(x); 8 | while (!q.empty()) { 9 | int s = q.front(); q.pop(); 10 | // process node s 11 | for (auto u : adj[s]) { 12 | if (visited[u]) continue; 13 | visited[u] = true; 14 | distance[u] = distance[s]+1; 15 | q.push(u); 16 | } 17 | } -------------------------------------------------------------------------------- /content/maths/mobius-sieve.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Compute the first values for the mobius funcion in $ O(n log(n)) $. 3 | *Status:* Tested in codeforces. 4 | */ 5 | vector mobius_sieve(int mxn){ 6 | vector mob(mxn+1); 7 | mob[1] = 1; 8 | for (int i = 2; i <= mxn; i++){ 9 | mob[i]--; 10 | for (int j = 2*i; j <= mxn; j += i) 11 | mob[j] -= mob[i]; 12 | } 13 | return mob; 14 | } -------------------------------------------------------------------------------- /content/maths/binary-pow-128-bits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Binary pow in 128 bits, computes $a^b mod m$ in $O(log b)$ 3 | *Status:* Highly tested 4 | */ 5 | using u64 = uint64_t; 6 | using u128 = __uint128_t; 7 | u64 binpow(u64 a, u64 b, u64 m) { 8 | a %= m; 9 | u64 res = 1; 10 | while (b > 0) { 11 | if (b & 1) 12 | res = (u128)res * a % m; 13 | a = (u128)a * a % m; 14 | b >>= 1; 15 | } 16 | return res; 17 | } -------------------------------------------------------------------------------- /content/general/template.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Just the starting template code 3 | */ 4 | #include 5 | 6 | using namespace std; 7 | 8 | using ll = long long; 9 | using ld = long double; 10 | 11 | const ll mod = 1e9 + 7; 12 | const ll inf = 1e12; 13 | const ld pi = acos(-1); 14 | 15 | int main() { 16 | ios::sync_with_stdio(0); cin.tie(0); 17 | cout << fixed << setprecision(9); 18 | 19 | return 0; 20 | } -------------------------------------------------------------------------------- /content/geometry/polygon-area.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the area of a polygon 3 | - If you want the double of the area, just enable the flag 4 | *Status:* Highly tested 5 | */ 6 | template 7 | T polygonArea(vector> P, bool x2 = 0) { 8 | T area = 0; 9 | for(int i = 0; i < P.size()-1; ++i) 10 | area += P[i]^(P[i+1]); 11 | // Si el primer punto se repite, sacar: 12 | area += (P.back())^(P.front()); 13 | return abs(area)/ (x2 ? 1 : 2); 14 | } -------------------------------------------------------------------------------- /content/geometry/order-by-angle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Sort the point depending their angle 3 | *Status:* Not tested 4 | */ 5 | template 6 | int semiplane(Point2D p) { return p.y > 0 or (p.y == 0 and p.x > 0); } 7 | 8 | template 9 | void orderByAngle(vector> &P) { 10 | sort(P.begin(), P.end(), [](Point2D &p1, Point2D &p2) { 11 | int s1 = semiplane(p1), s2 = semiplane(p2); 12 | return s1 != s2 ? s1 > s2 : (p1^p2) > 0; 13 | }); 14 | } -------------------------------------------------------------------------------- /content/algorithms/tortoise-hare.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Allow us to find cycles in any function 3 | *Status:* Not tested 4 | */ 5 | template 6 | pair tortoise_hare(T x0) { 7 | T t = f(x0); T h = f(f(x0)); 8 | while(t != h) t = f(t), h = f(f(h)); 9 | ll mu = 0; t = x0; 10 | while(t != h) t = f(t), h = f(h), mu++; 11 | ll lam = 1; h = f(t); 12 | while(t != h)h = f(h), lam += 1; 13 | // mu = start, lam = period 14 | return {mu, lam}; 15 | } -------------------------------------------------------------------------------- /content/maths/euler-phi-sieve.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Return $phi(n)$ for all positive $n$, runs on $O(n log ( log ( n ) ) )$ 3 | *Status:* Not tested 4 | */ 5 | struct euler_phi { 6 | vector phi; 7 | euler_phi(int n) { 8 | phi.resize(n + 1); 9 | for (int i = 1; i <= n; i++) 10 | phi[i] = i; 11 | for (int i = 2; i <= n; i++) { 12 | if (phi[i] == i) 13 | for (int j = i; j <= n; j += i) 14 | phi[j] = phi[j] / i * (i - 1); 15 | } 16 | } 17 | }; -------------------------------------------------------------------------------- /content/maths/pollard-rho.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Finds a non-trivial factor of a composite number $n$ using Pollard's Rho algorithm. 3 | *Status:* Partially tested 4 | */ 5 | ll pollard_rho(ll n) { 6 | if((n&1)^1) return 2; 7 | ll x = 2, y=2, d=1; 8 | ll c = rand()%n+1; 9 | while(d==1) { 10 | x=(mulmod(x,x,n)+c)%n; 11 | y=(mulmod(y,y,n)+c)%n; 12 | y=(mulmod(y,y,n)+c)%n; 13 | if(x>=y)d=__gcd(x-y,n); 14 | else d=__gcd(y-x,n); 15 | } 16 | return d==n? pollard_rho(n):d; 17 | } 18 | -------------------------------------------------------------------------------- /content/maths/factorial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Calculate factorials from $1$ to $n$ and their factorial, runs on $O(n)$ 3 | *Status:* Highly tested 4 | */ 5 | struct Factorial { 6 | vector f, finv, inv; ll mod; 7 | Factorial(ll n, ll mod): mod(mod) { 8 | f.assign(n+1, 1); inv.assign(n+1, 1); finv.assign(n+1, 1); 9 | for(ll i = 2; i <= n; ++i) 10 | inv[i] = mod - (mod/i) * inv[mod%i] % mod; 11 | for (ll i = 1; i <= n; ++i) { 12 | f[i] = (f[i-1] * i) % mod; 13 | finv[i] = (finv[i-1] * inv[i]) % mod; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /content/maths/erathostenes-sieve.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get all prime numbers up to $n$, runs on $O(n log(log (n)) ) $ 3 | *Status:* Highly tested 4 | */ 5 | struct eratosthenes_sieve { 6 | vector primes; 7 | vector isPrime; 8 | eratosthenes_sieve(ll n) { 9 | isPrime.resize(n + 1, true); 10 | isPrime[0] = isPrime[1] = false; 11 | for (ll i = 2; i <= n; i++) { 12 | if (isPrime[i]) { 13 | primes.push_back(i); 14 | for (ll j = i*i; j <= n; j += i) 15 | isPrime[j] = false; 16 | } 17 | } 18 | } 19 | }; -------------------------------------------------------------------------------- /content/graphs/dijkstra.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Antti Laaksonen 3 | *Description:* Computes shortest path in $O(V log (V + E) )$, does not allow negative weights 4 | */ 5 | for (int i = 1; i <= n; i++) distance[i] = INF; 6 | distance[x] = 0; 7 | q.push({0,x}); 8 | while (!q.empty()) { 9 | int a = q.top().second; q.pop(); 10 | if (processed[a]) continue; 11 | processed[a] = true; 12 | for (auto u : adj[a]) { 13 | int b = u.first, w = u.second; 14 | if (distance[a]+w < distance[b]) { 15 | distance[b] = distance[a]+w; 16 | q.push({-distance[b],b}); 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /content/geometry/halfplane.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Halfplane 3 | *Status:* Partially tested 4 | */ 5 | struct Halfplane { 6 | Point2D p, pq; 7 | ld angle; 8 | Halfplane() {} 9 | Halfplane(Point2D &a, Point2D &b) : p(a), pq(b - a) { 10 | angle = atan2l(pq.y, pq.x); 11 | } 12 | bool out(Point2D r) { return ((pq) ^ (r - p)) < -eps; } 13 | bool operator<(Halfplane &e) { return angle < e.angle; } 14 | friend Point2D inter(Halfplane &s, Halfplane &t) { 15 | ld alpha = ((t.p - s.p) ^ t.pq) / ((s.pq) ^ (t.pq)); 16 | return s.p + (s.pq * alpha); 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /content/strings/min-rotation.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Finds the lexicographically smallest rotation of a string, runs on $O(n)$ 3 | *Status:* Tested on CSES 4 | */ 5 | string minRotation(string &s) { 6 | int a = 0, N = s.size(); 7 | string res = s; s += s; 8 | for (int b = 0; b < N; b++) { 9 | for (int k = 0; k < N; k++) { 10 | if (a + k == b || s[a + k] < s[b + k]) { 11 | b += max(0, k - 1); break; 12 | } 13 | if (s[a + k] > s[b + k]) { 14 | a = b; break; 15 | } 16 | } 17 | } 18 | rotate(res.begin(), res.begin() + a, res.end()); 19 | return res; 20 | } -------------------------------------------------------------------------------- /content/graphs/floyd-warshall.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* All shortest path, runs on $O(V^3)$ 3 | *Status:* Tested 4 | */ 5 | 6 | // Create distance matrix 7 | for (int i = 1; i <= n; i++) { 8 | for (int j = 1; j <= n; j++) { 9 | if (i == j) distance[i][j] = 0; 10 | else if (adj[i][j]) distance[i][j] = adj[i][j]; 11 | else distance[i][j] = INF; 12 | } 13 | } 14 | 15 | // Floyd-Warshall 16 | for (int k = 1; k <= n; k++) { 17 | for (int i = 1; i <= n; i++) { 18 | for (int j = 1; j <= n; j++) { 19 | distance[i][j] = min(distance[i][j], distance[i][k]+distance[k][j]); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /content/maths/counting-divisors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description*: Counting divisors in $O(n ^ (1/3))$ 3 | *Status:* Tested on codeforces 4 | */ 5 | const int MX_P = 1e6 + 1; 6 | eratosthenes_sieve sieve(MX_P); 7 | int counting_divisors(int n) { 8 | int ret = 1; 9 | for (int p : sieve.primes) { 10 | if (p*p*p > n) break; 11 | int count = 1; 12 | while (n % p == 0) 13 | n /= p, count++; 14 | ret *= count; 15 | } 16 | int isqrt = sqrt(n); 17 | if (miller_rabin(n)) ret *= 2; 18 | else if (isqrt*isqrt == n and miller_rabin(isqrt)) ret *= 3; 19 | else if (n != 1) ret *= 4; 20 | return ret; 21 | } 22 | -------------------------------------------------------------------------------- /content/geometry/lattice-point.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* How many integers point are inside or in the bounds of the polygon 3 | - Only works for integers points 4 | *Status:* Tested on CSES 5 | */ 6 | pair latticePoints(vector> &P) { 7 | P.push_back(P.front()); 8 | int area = 0, bounds = 0; 9 | for(int i = 0; i < P.size()-1; ++i) { 10 | area += P[i]^(P[i+1]); 11 | Point2D p = P[i+1]-P[i]; 12 | bounds += abs(__gcd(p.x, p.y)); 13 | } 14 | int inside = (abs(area) - bounds + 2)/2; 15 | // Dejar el poligono como estaba antes 16 | P.pop_back(); 17 | return {inside, bounds}; 18 | } -------------------------------------------------------------------------------- /content/maths/tetration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Calculate$space ^(b)a mod m$ 3 | *Status:* Tested on josupo.jp 4 | */ 5 | map memophi; 6 | ll tetration(ll a, ll b, ll m) { 7 | if (m == 1) return 0; 8 | if (a == 0) return (b+1) % 2 % m; 9 | if (a == 1 or b == 0) return 1; 10 | if (b == 1) return a % m; 11 | if (a == 2 and b == 2) return 4 % m; 12 | if (a == 2 and b == 3) return 16 % m; 13 | if (a == 3 and b == 2) return 27 % m; 14 | if (memophi.find(m) == memophi.end()) 15 | memophi[m] = phi(m); 16 | ll tot = memophi[m]; 17 | ll n = tetration(a, b-1, tot); 18 | return binpow(a, (n < tot ? n + tot : n), m); 19 | } -------------------------------------------------------------------------------- /main.typ: -------------------------------------------------------------------------------- 1 | 2 | #set page( 3 | paper: "a4" 4 | ) 5 | 6 | #set text( 7 | font: "New Computer Modern", 8 | size: 13pt 9 | ) 10 | 11 | // Cover 12 | #align(center)[ 13 | #image(width: 150%, "img/utfsm_cp.png") 14 | ] 15 | 16 | #align(center)[ 17 | #text(size: 2.5em)[Handbook USM] 18 | ] 19 | 20 | *Maintainers:* 21 | - Gabriel Carmona (MrYhatoh) 22 | - Carlos Lagos (CharlesLakes) 23 | - Sebastián Torrealba (storrealbac) 24 | - Abner Vidal (abner_vidal) 25 | 26 | *Contributors:* 27 | - Javier Oliva (JOliva) 28 | - Marcelo Lemus (MarceloL) 29 | 30 | // Content 31 | #let content-file = read("content.typ") 32 | #eval(content-file, mode: "markup") 33 | -------------------------------------------------------------------------------- /content/geometry/point-inside-polygon.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Check if a point is inside, bounds or out of the polygon 3 | - 0: Bounds 4 | - 1: Inside 5 | - 2: Out 6 | *Status:* Tested 7 | */ 8 | template 9 | int pointInsidePolygon(vector> &P, Point2D q) { 10 | int N = P.size(), cnt = 0; 11 | for(int i = 0; i < N; i++) { 12 | int j = (i == N-1 ? 0 : i+1); 13 | Segment s(P[i], P[j]); 14 | if(s.contain(q)) return 0; 15 | if(P[i].x <= q.x and q.x < P[j].x and q.cross(P[i], P[j]) < 0) cnt++; 16 | else if(P[j].x <= q.x and q.x < P[i].x and q.cross(P[j], P[i]) < 0) cnt++; 17 | } 18 | return cnt&1 ? 1 : -1; 19 | } -------------------------------------------------------------------------------- /content/data-structures/union-find.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Finds sets and merges elements, complexity $O( alpha(n))$. $alpha(10^(600)) approx 4$ 3 | *Status:* Highly tested 4 | */ 5 | struct union_find { 6 | vector e; 7 | union_find(int n) { e.assign(n, -1); } 8 | int findSet (int x) { 9 | return (e[x] < 0 ? x : e[x] = findSet(e[x])); 10 | } 11 | bool sameSet (int x, int y) { return findSet(x) == findSet(y); } 12 | int size (int x) { return -e[findSet(x)]; } 13 | bool unionSet (int x, int y) { 14 | x = findSet(x), y = findSet(y); 15 | if (x == y) return 0; 16 | if (e[x] > e[y]) swap(x, y); 17 | e[x] += e[y], e[y] = x; 18 | return 1; 19 | } 20 | }; -------------------------------------------------------------------------------- /content/maths/poly-shift.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Solves $f(x + c) = sum_0^(n-1) b_i dot x^i$ 3 | *Status:* Tested 4 | */ 5 | vector polyShift(vector &a, int shift) { 6 | // change for any mod for ntt 7 | const int mod = 998244353; 8 | NTT<998244353, 3> ntt; 9 | int n = a.size() - 1; 10 | Factorial f(n, mod); 11 | vector x(n+1), y(n+1); 12 | int cur = 1; 13 | for (int i = 0; i <= n; i++) { 14 | x[i] = cur * f.finv[i] % mod; 15 | cur = (cur * shift) % mod; 16 | y[i] = a[n - i] * f.f[n-i] % mod; 17 | } 18 | vector tmp = ntt.conv(x, y), res(n+1); 19 | for (int i = 0; i <= n; i++) 20 | res[i] = tmp[n-i] * f.finv[i] % mod; 21 | return res; 22 | } -------------------------------------------------------------------------------- /content/strings/rolling-hashing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Rolling hash for fast substring comparison, single hash function 3 | *Status:* Tested 4 | */ 5 | template 6 | struct rolling_hashing { 7 | int base, mod; 8 | vector p, H; 9 | int n; 10 | rolling_hashing(const T &s, int b, int m): base(b), mod(m), n(s.size()) { 11 | p.assign(n+1, 1); 12 | H.assign(n+1, 0); 13 | for (int i = 0; i < n; ++i) { 14 | H[i+1] = (H[i] * base + s[i]) % mod; 15 | p[i+1] = (p[i] * base) % mod; 16 | } 17 | } 18 | int get(int l, int r) { 19 | int res = (H[r+1] - H[l]*p[r-l+1]) % mod; 20 | if (res < 0) res += mod; 21 | return res; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /content/dynamic-programming/knuth.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Knuth-Yao optimization for DP (optimal binary search trees) 3 | *Status:* Tested 4 | */ 5 | int N; 6 | vector A; 7 | vector> DP, OPT; 8 | int main() { 9 | DP.assign(N + 1, vi(N + 1)); 10 | OPT.assign(N + 1, vi(N + 1)); 11 | rep(i, N) { 12 | DP[i][i + 1] = A[i + 1] - A[i]; 13 | OPT[i][i + 1] = i; 14 | } 15 | repx(d, 2, N + 1) 16 | rep(l, N + 1 - d) { 17 | int r = l + d, l_ = OPT[l][r - 1], r_ = OPT[l + 1][r]; 18 | DP[l][r] = 1e9; 19 | repx(i, l_, r_ + 1) { 20 | int aux = DP[l][i] + DP[i][r] + A[r] - A[l]; 21 | if (aux < DP[l][r]) DP[l][r] = aux, OPT[l][r] = i; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /.github/workflows/check-tracker.yml: -------------------------------------------------------------------------------- 1 | name: check-tracker 2 | 3 | on: 4 | push: 5 | branches: [ "*" ] 6 | pull_request: 7 | branches: [ "*" ] 8 | 9 | jobs: 10 | check-tracker: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v2 15 | 16 | - name: Set up Python 17 | uses: actions/setup-python@v2 18 | with: 19 | python-version: '3.8' 20 | 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install pyyaml 25 | 26 | - name: Run check-tracker 27 | run: | 28 | python scripts/check-tracker.py tracker.yaml content 29 | -------------------------------------------------------------------------------- /.github/workflows/test-compile.yml: -------------------------------------------------------------------------------- 1 | name: test-compile 2 | 3 | on: 4 | pull_request: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | test-compile: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Install Typst 16 | run: | 17 | wget https://github.com/typst/typst/releases/latest/download/typst-x86_64-unknown-linux-musl.tar.xz 18 | tar -xf typst-x86_64-unknown-linux-musl.tar.xz 19 | sudo mv typst-x86_64-unknown-linux-musl/typst /usr/local/bin/ 20 | 21 | - name: Test Compile 22 | run: | 23 | typst compile main.typ 24 | ls -al main.pdf # Verify compilation succeeded -------------------------------------------------------------------------------- /content/data-structures/min-stack.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the minumum element of the stack, runs on $O(1)$ $O(1)$ per operation amortized. Can be modified to get the maximum just changing the function 3 | *Status:* Tested on Maximum Subarray Sum II CSES 4 | */ 5 | template 6 | struct min_stack { 7 | vector> S; 8 | void push(T x) { 9 | T new_min = S.empty() ? x : min(x, S.back().second); 10 | S.push_back({x, new_min}); 11 | } 12 | bool empty() { return S.empty(); } 13 | int size() { return S.size(); } 14 | void pop() { S.pop_back(); } 15 | T top() { return S.back().first; } 16 | T getmin() { return S.back().second; } 17 | void swap(min_stack & other) noexcept { S.swap(other.S); } 18 | }; 19 | -------------------------------------------------------------------------------- /content/graphs/mfed.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Max flow but with lowerbound of flow for each edge. To check is a feasible solution, all edges of super-sink (N) node should be saturated 3 | *Status:* Tested 4 | */ 5 | struct max_flow_edge_demands { 6 | Dinic mf; 7 | vector in, out; 8 | ll N; 9 | max_flow_edge_demands(ll N): N(N), mf(N+2), in(N), out(N) {} 10 | void add_edge(ll u, ll v, ll cap, ll dem = 0) { 11 | mf.add_edge(u, v, cap - dem); 12 | out[u] += dem, in[v] += dem; 13 | } 14 | ll max_flow(ll s, ll t) { 15 | mf.add_edge(t, s, inf); 16 | for (ll i = 0; i < N; i++) { 17 | mf.add_edge(N, i, in[i]); 18 | mf.add_edge(i, N+1, out[i]); 19 | } 20 | return mf.max_flow(N, N+1); 21 | } 22 | }; -------------------------------------------------------------------------------- /content/maths/fraction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Just a fraction, every operation runs on $O(log(min(p, q)))$ 3 | *Status:* Not tested 4 | */ 5 | #define lcm(a, b) ( gcd(a, b) ? ( (a)*(b) ) / gcd(a, b) ): 0 6 | template 7 | struct Fraction { 8 | T p, q; 9 | Fraction() {} 10 | Fraction(T p, T q): p(p), q(q) { 11 | if (q < 0) this->p = -p, this->q = -q; 12 | } 13 | bool operator<(const Fraction o) { 14 | return p*o.q < o.p*q; 15 | } 16 | Fraction simplify(Fraction f){ 17 | ll g = __gcd(f.p, f.q); 18 | return Fraction(f.p/g, f.q/g); 19 | } 20 | Fraction add(Fraction f){ 21 | ll l = lcm(q, f.q); 22 | p *= (l/q); 23 | p += f.p * (l/f.q); 24 | return simplify(Fraction(p, l)); 25 | } 26 | }; -------------------------------------------------------------------------------- /content/maths/crt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Chinese remainder theorem 3 | *Status:* Stress-tested 4 | */ 5 | using lll = __int128_t; 6 | ll crt(vector a, vector m) { 7 | int n = a.size(); 8 | for (int i = 0; i < n; i++) { 9 | a[i] %= m[i]; 10 | a[i] = a[i] < 0 ? a[i] + m[i] : a[i]; 11 | } 12 | lll ans = a[0]; 13 | lll M = m[0]; 14 | for (int i = 1; i < n; i++) { 15 | auto pom = ex_GCD(M, m[i]); 16 | lll x1 = pom.x; 17 | lll d = pom.d; 18 | if ((a[i] - ans) % d != 0) 19 | return -1; 20 | ans = ans + x1 * (a[i] - ans) / d % (m[i] / d) * M; 21 | M = M * m[i] / d; 22 | ans %= M; 23 | ans = ans < 0 ? ans + M : ans; 24 | M = M / (lll)__gcd((ll)M, (ll)m[i]) * m[i]; 25 | } 26 | return ans; 27 | } 28 | -------------------------------------------------------------------------------- /content/maths/sieveking-kung.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Computes the first n elements of the inverse series of a polynomial, 3 | requires fast_ntt, and good modulus. 4 | *Status:* Tested on yosupo 5 | */ 6 | using ull = uint64_t; 7 | const ull mod = 998244353, pr = 3; 8 | vector sieveking_kung(vector a, int n) { 9 | vector ans = {bin_pow(a[0],mod-2,mod)}; 10 | fast_ntt pol; 11 | for (int i = 1; i < n; i <<= 1) { 12 | vector a_trunc(a.begin(),a.begin()+min((int)a.size(),2*i)); 13 | vector res = pol.conv(ans,a_trunc); 14 | res = pol.conv(res,ans); res.resize(2*i); 15 | for (int j = 0; j < 2 * i; ++j) 16 | res[j] = ((j < (int)ans.size()?2*ans[j]:0ULL)+mod-res[j])%mod; 17 | ans = res; 18 | } 19 | ans.resize(n); 20 | return ans; 21 | } -------------------------------------------------------------------------------- /content/data-structures/bit.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries and updates, precomputed $O(n log n)$, query/update $O(log n)$ 3 | - Sum operation can be changed to xor 4 | *Status:* Tested 5 | */ 6 | struct fenwick_tree { 7 | vector bit; int n; 8 | fenwick_tree(int n): n(n) { bit.assign(n, 0); } 9 | fenwick_tree(vector &a): fenwick_tree(a.size()) { 10 | for (size_t i = 0; i < a.size(); i++) 11 | add(i, a[i]); 12 | } 13 | int sum(int r) { 14 | int ret = 0; 15 | for (; r >= 0; r = (r & (r + 1)) - 1) 16 | ret += bit[r]; 17 | return ret; 18 | } 19 | int sum(int l, int r) { 20 | return sum(r) - sum(l - 1); 21 | } 22 | void add(int idx, int delta) { 23 | for (; idx < n; idx = idx | (idx + 1)) 24 | bit[idx] += delta; 25 | } 26 | }; -------------------------------------------------------------------------------- /content/maths/discrete-log.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Marcos Kolodny (MarcosK) 3 | *Description:* Returns $x$ such that $a^x = b (mod m)$ or $-1$ if inexistent 4 | *Status:* Tested on josupo.jp 5 | */ 6 | ll discrete_log(ll a,ll b,ll m) { 7 | a%=m, b%=m; 8 | if(b == 1) return 0; 9 | int cnt=0, tmp=1; 10 | for(int g=__gcd(a,m);g!=1;g=__gcd(a,m)) { 11 | if(b%g) return -1; 12 | m/=g, b/=g; 13 | tmp = tmp*a/g%m; 14 | ++cnt; 15 | if(b == tmp) return cnt; 16 | } 17 | map w; 18 | int s = ceil(sqrt(m)), base = b; 19 | for (int i = 0; i < s; i++) 20 | w[base] = i, base=base*a%m; 21 | base=binpow(a,s,m); 22 | ll key=tmp; 23 | for(int i = 1; i < s+2; i++) { 24 | key=base*key%m; 25 | if(w.count(key)) return i*s-w[key]+cnt; 26 | } 27 | return -1; 28 | } -------------------------------------------------------------------------------- /content/maths/non-deterministic-miller-rabin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Miller rabin using probabilistic algorithm 3 | *Status:* Partially tested 4 | */ 5 | bool nd_miller_rabin(ll n) { 6 | if (n == 1) return false; 7 | auto is_prime_prob = [&](ll n, ll a){ 8 | if (n == a) return true; 9 | ll s = 0, d = n-1; 10 | while (d%2==0) s++, d/=2; 11 | ll x = binpow(a, d, n); 12 | if ( (x==1) or (x+1 == n)) return true; 13 | for(ll i = 0; i < s-1; i++) { 14 | x = mulmod(x, x, n); 15 | if (x == 1) return false; 16 | if (x+1 == n) return true; 17 | } 18 | return false; 19 | }; 20 | int primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 23}; 21 | for (ll i = 0; i < 9; i++) 22 | if (!is_prime_prob(n, primes[i])) 23 | return false; 24 | return true; 25 | } 26 | -------------------------------------------------------------------------------- /content/maths/miller-rabin.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Detect if a number is prime or not in $O(log^2(n))$, needs 128 bits binary pow 3 | *Status:* Highly tested 4 | */ 5 | bool miller_rabin(uint64_t n) { 6 | if (n <= 1) return false; 7 | auto check = [](uint64_t n, uint64_t a, uint64_t d, uint64_t s) { 8 | int x = binpow(a, d, n); // Usar binpow de 128bits 9 | if (x == 1 or x == n-1) return false; 10 | for (int r = 1; r < s; r++) { 11 | x = (__uint128_t)x*x % n; 12 | if (x == n-1) return false; 13 | } 14 | return true; 15 | }; 16 | uint64_t r = 0, d = n - 1; 17 | while ((d & 1) == 0) d >>= 1, r++; 18 | for (int x : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) { 19 | if (x == n) return true; 20 | if (check(n, x, d, r)) return false; 21 | } 22 | return true; 23 | } -------------------------------------------------------------------------------- /content/maths/montgomery.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Optimizes multiplication with large modules, useful for fast_ntt. 3 | *Status:* Tested on codeforces. 4 | */ 5 | using ull = uint64_t 6 | struct montgomery { 7 | ull n, nr; 8 | constexpr montgomery(ull n) : n(n), nr(1) { 9 | for (int i = 0; i < 6; i++) 10 | nr *= 2 - n * nr; 11 | } 12 | ull reduce(__uint128_t x) const { 13 | ull q = __uint128_t(x) * nr; 14 | ull m = ((__uint128_t) q * n) >> 64; 15 | ull res = (x >> 64) + n - m; 16 | if (res >= n) 17 | res -= n; 18 | return res; 19 | } 20 | ull multiply(ull x, ull y) const { 21 | return reduce((__uint128_t) x * y); 22 | } 23 | ull transform(ull x) const { 24 | return (__uint128_t(x) << 64) % n; 25 | } 26 | }; -------------------------------------------------------------------------------- /content/maths/divisors.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Sebastian Torrealba 3 | *Description:* Get all divisors in $O( sqrt(n) )$, it includes $1$ and $n$ 4 | *Status:* Highly tested 5 | */ 6 | vector get_divisors(ll n) { 7 | vector left, right, ans; 8 | for (ll i = 1; i * i <= n; i++) 9 | if (n % i == 0) { 10 | if (i != n / i) 11 | right.push_back(n / i); 12 | left.push_back(i); 13 | } 14 | ans.resize(left.size() + right.size()); 15 | reverse(begin(right), end(right)); 16 | ll i = 0, j = 0; 17 | while (i < left.size() and j < right.size()) { 18 | if (left[i] < right[j]) 19 | ans[i + j - 1] = left[i++]; 20 | else ans[i + j - 1] = right[j++]; 21 | } 22 | while(i < left.size()) ans[i + j - 1] = left[i++]; 23 | while(j < right.size()) ans[i + j - 1] = right[j++]; 24 | return ans; 25 | } -------------------------------------------------------------------------------- /content/dynamic-programming/egg-drop.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Egg dropping problem with binary search optimization 3 | *Status:* Tested 4 | */ 5 | vector> egg_drop(ll h,ll k){ 6 | vector> dp(h + 1,vector(k + 1)); 7 | for(int i = 0; i < k + 1; i++) dp[0][i] = 0; 8 | for(int i = 1; i < h + 1; i++) dp[i][0] = INT_MAX; 9 | for(int j = 1; j < k + 1; j++) { 10 | for(int i = 1; i < h + 1; i++) { 11 | ll ans=INT_MAX,x=1,y=i; 12 | while(x <= y){ 13 | ll mid = (x + y)/2; 14 | ll bottom = dp[mid - 1][j - 1]; 15 | ll top = dp[i - mid][j]; 16 | ll temp = max(bottom,top); 17 | if(bottom < top) 18 | x = mid + 1; 19 | else y = mid - 1; 20 | ans = min(ans,temp); 21 | } 22 | dp[i][j] = 1 + ans; 23 | 24 | } 25 | } 26 | return dp; 27 | } -------------------------------------------------------------------------------- /content/data-structures/bit-2d.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* 2D Range queries, Runs on $O(log n dot log m)$ per operation 3 | *Status:* Tested 4 | */ 5 | struct fenwick_tree_2d { 6 | int N, M; 7 | vector < vector < int >> BIT; 8 | fenwick_tree_2d(int N, int M): N(N), M(M) { 9 | BIT.assign(N + 1, vector < int > (M + 1, 0)); 10 | } 11 | void update(int x, int y, int v) { 12 | for (int i = x; i <= N; i += (i & -i)) 13 | for (int j = y; j <= M; j += (j & -j)) 14 | BIT[i][j] += v; 15 | } 16 | int sum(int x, int y) { 17 | int s = 0; 18 | for (int i = x; i > 0; i -= (i & -i)) 19 | for (int j = y; j > 0; j -= (j & -j)) 20 | s += BIT[i][j]; 21 | return s; 22 | } 23 | int query(int x1, int y1, int x2, int y2) { 24 | return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1); 25 | } 26 | }; -------------------------------------------------------------------------------- /content/dynamic-programming/d&c.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Divide and conquer optimization for DP with quadrangle inequality 3 | *Status:* Tested 4 | */ 5 | // dp(i, j) = min dp(i-1,k-1) + C(k,j) for all k in [0, j] 6 | // C(a,c) + C(b, d) <= C(a,d) + C(b,c) for all a <= b <= c <= d 7 | vp c; 8 | vl acum1, acum2; 9 | ll cost(ll i, ll j) { 10 | return c[j].first * (acum1[j+1] - acum1[i]) - (acum2[j+1] - acum2[i]); 11 | } 12 | vector last, now; 13 | void compute(int l, int r, int optl, int optr) { 14 | if (l > r) return; 15 | int mid = (l + r) / 2; 16 | pair best = {cost(0, mid), -1}; 17 | for(int k = max(1, optl); k < min(mid, optr) + 1; k++) 18 | best = min(best, {last[k - 1] + cost(k, mid), k}); 19 | now[mid] = best.first; 20 | compute(l, mid - 1, optl, best.second); 21 | compute(mid + 1, r, best.second, optr); 22 | } -------------------------------------------------------------------------------- /content/graphs/bridges.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the bridges to given graph, runs on $O(V + E)$ 3 | *Status:* Tested 4 | */ 5 | struct Bridges { 6 | int n, timer; 7 | vector tin, low, vis; 8 | vector > bridges; 9 | Bridges(vector > &adj, int root = 0) { 10 | n = adj.size(); 11 | timer = 0; 12 | vis.resize(n, false); 13 | tin.resize(n); 14 | low.resize(n); 15 | dfs(root, root, adj); 16 | } 17 | void dfs(int v, int p, vector > &adj) { 18 | vis[v] = 1; tin[v] = low[v] = timer++; 19 | for (int to: adj[v]) { 20 | if (to == p) continue; 21 | if (vis[to]) low[v] = min(low[v], tin[to]); 22 | else { 23 | dfs(to, v, adj); 24 | low[v] = min(low[v], low[to]); 25 | if (low[to] > tin[v]) bridges.push_back({v,to}); 26 | } 27 | } 28 | } 29 | }; -------------------------------------------------------------------------------- /content/graphs/chromatic-number.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Computes the chromatic number of a graph in $O(2^{n}n)$ 3 | *Status:* Tested 4 | */ 5 | int chromatic(vector & adj){ 6 | int n = adj.size(); 7 | if (n == 0) return 0; 8 | ll mod = 998244353, m = (1< ind(m),s(m); 10 | for (int i = 0; i < m; i++) 11 | s[i] = ((n-__builtin_popcount(i))&1?-1:1); 12 | ind[0] = 1; 13 | for (int i = 1; i < m; i++){ 14 | int ctz = __builtin_ctz(i); 15 | ind[i] = (ind[i-(1<= l where ST[i] >= k, or -1 if none exists. Walk O(log n). 3 | *Status:* Partially tested 4 | */ 5 | template struct segment_tree_with_walk : segment_tree { 6 | int walk(int l, T k) { 7 | vector L, R; 8 | int r = this->n - 1; 9 | for (l += this->n, r += this->n + 1; l < r; l >>= 1, r >>= 1) { 10 | if (l & 1) L.push_back(l++); 11 | if (r & 1) R.push_back(--r); 12 | } 13 | reverse(R.begin(), R.end()); 14 | L.insert(L.end(), R.begin(), R.end()); 15 | for (int v : L) { 16 | if (this->ST[v] >= k) { 17 | while (v < this->n) v = (this->ST[v << 1] >= k) ? (v << 1) : (v << 1 | 1); 18 | return v - this->n; 19 | } 20 | } 21 | return -1; 22 | } 23 | }; -------------------------------------------------------------------------------- /content/graphs/kruskal.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Minimum spanning tree in $O(E log E)$ 3 | *Status:* Tested 4 | */ 5 | struct Edge { 6 | int a; int b; int w; 7 | Edge(int a_, int b_, int w_) : a(a_), b(b_), w(w_) {} 8 | }; 9 | bool c_edge(Edge &a, Edge &b) { return a.w < b.w; } 10 | int Kruskal() { 11 | int n = G.size(); 12 | union_find sets(n); 13 | vector< Edge > edges; 14 | for(int i = 0; i < n; i++) { 15 | for(auto eg : G[i]) { 16 | // node i to node eg.first with cost eg.second 17 | edges.emplace_back(i, eg.first, eg.second); 18 | } 19 | } 20 | sort(edges.begin(), edges.end(), c_edge); 21 | int min_cost = 0; 22 | for(Edge e : edges) { 23 | if(sets.sameSet(e.a, e.b) != true) { 24 | tree.emplace_back(e.a, e.b, e.w); 25 | min_cost += e.w; 26 | sets.unionSet(e.a, e.b); 27 | } 28 | } 29 | return min_cost; 30 | } 31 | -------------------------------------------------------------------------------- /content/dynamic-programming/lis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Longest increasing subsequence in $O(n log n)$, allow us to recover the sequence 3 | *Status:* Highly tested 4 | */ 5 | template vector LIS(const vector &S) { 6 | if (S.empty()) return {}; 7 | vector prev(S.size()); 8 | vector> res; 9 | for (int i = 0; i < S.size(); i++) { 10 | auto it = lower_bound(res.begin(), res.end(), pair{S[i], i}); 11 | if (it == res.end()) res.emplace_back(), it = res.end() - 1; 12 | *it = {S[i], i}; 13 | prev[i] = (it == res.begin() ? 0 : (it - 1)->second); 14 | } 15 | int L = res.size(), cur = res.back().second; 16 | vector ans(L); 17 | while (L--) ans[L] = cur, cur = prev[cur]; 18 | /* Recover the sequence 19 | for (int i = 0; i+1 < ans.size(); i++) 20 | ans[i] = S[ans[i]]; 21 | */ 22 | return ans; 23 | } -------------------------------------------------------------------------------- /content/data-structures/min-queue.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the minumum element of the queue, runs on $O(1)$ per operation amortized. Can be modified to get the maximum just changing the function 3 | *Status:* Tested on Maximum Subarray Sum II CSES 4 | */ 5 | template 6 | struct min_queue { 7 | min_stack in, out; 8 | void push(T x) { in.push(x); } 9 | bool empty() { return in.empty() and out.empty(); } 10 | int size() { return in.size() + out.size(); } 11 | void pop() { 12 | if (out.empty()) 13 | for (;in.size(); in.pop()) out.push(in.top()); 14 | out.pop(); 15 | } 16 | T front() { 17 | if (!out.empty()) return out.top(); 18 | for (;in.size(); in.pop()) out.push(in.top()); 19 | return out.top(); 20 | } 21 | T getMin() { 22 | if (in.empty()) return out.getMin(); 23 | if (out.empty()) return in.getMin(); 24 | return min(in.getMin(), out.getMin()); 25 | } 26 | }; 27 | -------------------------------------------------------------------------------- /content/algorithms/mo.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Allow us to answer queries offline with sqrt decomposition 3 | *Status:* Tested 4 | */ 5 | struct query { 6 | ll l, r, i; 7 | }; 8 | template 9 | struct mo_algorithm { 10 | vector ans; 11 | template 12 | mo_algorithm(vector &v, vector &queries, Args... args) { 13 | T2 ds(args...); 14 | ll block_sz = sqrtl(v.size()); 15 | ans.assign(queries.size(), -1); 16 | sort(queries.begin(), queries.end(), [&](auto &a, auto &b) { 17 | return a.l/block_sz != b.l/block_sz ? a.l/block_sz < b.l/block_sz : a.r < b.r; 18 | }); 19 | ll l = 0, r = -1; 20 | for (query q : queries) { 21 | while (l > q.l) ds.add(v[--l]); 22 | while (r < q.r) ds.add(v[++r]); 23 | while (l < q.l) ds.remove(v[l++]); 24 | while (r > q.r) ds.remove(v[r--]); 25 | ans[q.i] = ds.answer(q); 26 | } 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /content/data-structures/succinct-indexable-dictionary.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Space-efficient bit vector with rank support 3 | *Status:* Tested 4 | */ 5 | struct succinct_indexable_dictionary { 6 | size_t len, blocks; 7 | vector bit, sum; 8 | succinct_indexable_dictionary() = default; 9 | succinct_indexable_dictionary(size_t len) : len(len), blocks((len + 31)>>5) { 10 | bit.assign(blocks, 0U); 11 | sum.assign(blocks, 0U); 12 | } 13 | void set(int k) { bit[k >> 5] |= 1U << (k & 31); } 14 | void build() { 15 | sum[0] = 0U; 16 | for (int i = 1; i < blocks; i++) 17 | sum[i] = sum[i - 1] + __builtin_popcount(bit[i - 1]); 18 | } 19 | bool operator[](int k) { return (bool((bit[k >> 5] >> (k & 31)) & 1)); } 20 | int rank(int k) { 21 | return (sum[k >> 5] + __builtin_popcount(bit[k >> 5] & ((1U << (k & 31)) - 1))); 22 | } 23 | int rank(bool val, int k) { return (val ? rank(k) : k - rank(k)); } 24 | }; 25 | -------------------------------------------------------------------------------- /content/strings/k-rolling-hashing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Rolling hash with multiple hash functions for collision resistance 3 | *Status:* Tested 4 | */ 5 | template 6 | struct rolling_hashing { 7 | vector base, mod; int n, k; 8 | vector> p, H; 9 | rolling_hashing(T s, vector b, vector m): base(b), mod(m), n(s.size()), k(b.size()) { 10 | p.resize(k); H.resize(k); 11 | for (int j = 0; j < k; j++) { 12 | p[j].assign(n + 1, 1); 13 | H[j].assign(n + 1, 0); 14 | for (int i = 0; i < n; i++) { 15 | H[j][i + 1] = (H[j][i] * b[j] + s[i]) % mod[j]; 16 | p[j][i + 1] = (p[j][i] * b[j]) % mod[j]; 17 | } 18 | } 19 | } 20 | vector get(int l, int r) { 21 | vector res(k); 22 | for (int j = 0; j < k; j++) { 23 | res[j] = H[j][r + 1] - H[j][l] * p[j][r - l + 1]; 24 | res[j] %= mod[j]; 25 | res[j] = (res[j] + mod[j]) % mod[j]; 26 | } 27 | return res; 28 | } 29 | }; -------------------------------------------------------------------------------- /content/data-structures/sparse-table.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries, precomputed $O(n log n)$, query $O(1)$. 3 | - Only supports queries of idempotent functions (min, max, gcd) 4 | - Does not allow updates 5 | *Status:* Highly tested 6 | */ 7 | template 8 | struct sparse_table { 9 | int n; 10 | vector> table; 11 | sparse_table() {} 12 | sparse_table(vector &arr) { 13 | n = arr.size(); 14 | int k = log2_floor(n) + 1; 15 | table.assign(n, vector(k)); 16 | for (int i = 0; i < n; i++) 17 | table[i][0] = arr[i]; 18 | for (int j = 1; j < k; j++) 19 | for (int i = 0; i + (1 << j) <= n; i++) 20 | table[i][j] = m_(table[i][j-1], table[i+(1<<(j-1))][j-1]); 21 | } 22 | T query(int l, int r) { 23 | int k = log2_floor(r - l + 1); 24 | return m_(table[l][k], table[r-(1 << k)+1][k]); 25 | } 26 | int log2_floor(int n) { return n ? __builtin_clzll(1) - __builtin_clzll(n) : -1; } 27 | }; 28 | -------------------------------------------------------------------------------- /content/graphs/articulation-points.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Finds articulation points in a graph using DFS. Runs on $O(V + E)$ 3 | *Status:* Tested on CSES 4 | */ 5 | struct ArticulationPoints { 6 | int n, timer; 7 | vector tin, low, vis; 8 | set points; 9 | void dfs(int v, int p, vector> &adj) { 10 | vis[v] = true; tin[v] = low[v] = timer++; 11 | int child = 0; 12 | for (int to: adj[v]) { 13 | if (to == p) continue; 14 | if (vis[to]) low[v] = min(low[v], tin[to]); 15 | else { 16 | dfs(to, v, adj); 17 | low[v] = min(low[v], low[to]); 18 | if ((low[to] >= tin[v]) && (p != -1)) 19 | points.insert(v); 20 | child++; 21 | } 22 | } 23 | if ((p == -1) && (child > 1)) points.insert(v); 24 | } 25 | ArticulationPoints(vector < vector < int >> & adj, int root = 0) { 26 | n = adj.size(); 27 | vis.resize(n, false); 28 | tin.resize(n); 29 | low.resize(n); 30 | dfs(root, -1, adj); 31 | } 32 | }; -------------------------------------------------------------------------------- /content/dynamic-programming/convex-hull-trick.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Given lines mantains a convex space to maximum queries, $a$ is the slope and $b$ the constant. 3 | *Important:* Sort slopes before use 4 | *Status:* Partially tested 5 | */ 6 | struct convex_hull_trick { 7 | vector A, B; 8 | const ll inf = numeric_limits::max()/4; 9 | double cross(ll i, ll j, ll k) { 10 | return 1.0*(A[j] - A[i]) * (B[k] - B[i]) - 1.0*(A[k] - A[i]) * (B[j] - B[i]); 11 | } 12 | void add(ll a, ll b) { 13 | A.push_back(a), B.push_back(b); 14 | while(A.size() > 2 and cross(A.size() - 3, A.size() - 2, A.size() - 1) <= 0) 15 | A.erase(A.end() - 2), B.erase(B.end() - 2); 16 | } 17 | ll query(ll x) { 18 | if(A.empty()) return inf; 19 | ll l = 0, r = A.size() - 1; 20 | while (l < r) { 21 | ll mid = (l + r)/2; 22 | ll f1 = A[mid] * x + B[mid]; 23 | ll f2 = A[mid + 1] * x + B[mid + 1]; 24 | if(f1 > f2) l = mid + 1; 25 | else r = mid; 26 | } 27 | return A[l] * x + B[l]; 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /content/data-structures/merge-sort-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Iterative merge sort tree. Each node stores sorted elements in its range. 3 | - Query: Count elements > k in range [i, j]. O(log^2 n) per operation. 4 | - Build: O(n log n) 5 | *Status:* Distinct Values Queries (CSES) 6 | */ 7 | template 8 | struct merge_sort_tree { 9 | int N; vector> ST; 10 | merge_sort_tree(){} 11 | merge_sort_tree(vector &vs) { 12 | N = vs.size(); ST.resize(2 * N); 13 | for (int i = 0; i < N; i++) ST[i + N] = {vs[i]}; 14 | for (int i = N - 1; i > 0; i--) 15 | merge(ST[i<<1].begin(), ST[i<<1].end(), ST[i<<1|1].begin(), ST[i<<1|1].end(), back_inserter(ST[i])); 16 | } 17 | int query(int i, int j, int k) { 18 | int res = 0; 19 | for (i += N, j += N + 1; i < j; i >>= 1, j >>= 1) { 20 | if (i & 1) res += ST[i].size() - (upper_bound(ST[i].begin(), ST[i].end(), k) - ST[i].begin()), i++; 21 | if (j & 1) --j, res += ST[j].size() - (upper_bound(ST[j].begin(), ST[j].end(), k) - ST[j].begin()); 22 | } 23 | return res; 24 | } 25 | }; 26 | -------------------------------------------------------------------------------- /content/geometry/segment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Segment implementation 3 | *Status:* Partially tested 4 | */ 5 | template 6 | struct Segment { 7 | Point2D< T > P; 8 | Point2D< T > Q; 9 | const T INF = numeric_limits::max(); 10 | Segment(Point2D P, Point2D Q): P(P), Q(Q) {} 11 | int sign(T x, T eps = 0) { return x > eps ? 1 : x < -eps ? -1 : 0; } 12 | bool contain(Point2D p, T eps = 0) { 13 | return ((P - p)|(Q - p)) <= (T)0 and abs(((Q - P)^(p - P))) <= eps; 14 | } 15 | bool intersect(Segment b) { 16 | if (this->contain(b.P) or this->contain(b.Q) or b.contain(P) or b.contain(Q)) 17 | return true; 18 | // change < 0 or <= depending the problem 19 | return sign((((b.P) - P))^((Q - P)))*sign(((b.Q - P)^(Q - P))) < 0 and 20 | sign(((P - b.Q)^(b.Q - b.P)))*sign(((Q- b.P)^(b.Q - b.P))) < 0; 21 | } 22 | // not tested 23 | Point2D intersection(Segment b) { 24 | if(this->intersect(b)) 25 | return (((b.Q-b.P)^(Q-b.P))*P + ((P-b.P)^(b.Q-b.P))*Q)/((P-Q)^(b.Q-b.P)); 26 | return {INF, INF}; 27 | } 28 | }; -------------------------------------------------------------------------------- /content/data-structures/segment-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries, build $O(n)$, query and update $O(log n)$, positions [0, n - 1] 3 | *Status:* Highly tested 4 | */ 5 | template struct segment_tree{ 6 | int n; vector ST; 7 | segment_tree(){} 8 | segment_tree(vector &a){ 9 | n = a.size(); ST.resize(n << 1); 10 | for (int i=n;i<(n<<1);i++)ST[i]=a[i-n]; 11 | for (int i=n-1;i>0;i--)ST[i]=m_(ST[i<<1],ST[i<<1|1]); 12 | } 13 | void update(int pos, T val){ // replace with val 14 | ST[pos += n] = val; 15 | for (pos >>= 1; pos > 0; pos >>= 1) 16 | ST[pos] = m_(ST[pos<<1], ST[pos<<1|1]); 17 | } 18 | T query(int l, int r){ // [l, r] 19 | T ansL, ansR; bool hasL = 0, hasR = 0; 20 | for (l += n, r += n + 1; l < r; l >>= 1, r >>= 1) { 21 | if (l & 1) 22 | ansL=(hasL?m_(ansL,ST[l++]):ST[l++]),hasL=1; 23 | if (r & 1) 24 | ansR=(hasR?m_(ST[--r],ansR):ST[--r]),hasR=1; 25 | } 26 | if (!hasL) return ansR; if (!hasR) return ansL; 27 | return m_(ansL, ansR); 28 | } 29 | }; 30 | -------------------------------------------------------------------------------- /content/graphs/lca-rmq.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Computes lowest common ancestor, precomputed in $O(V log V)$, $O(1)$ per query. Rooted in 0 3 | *Status:* Tested on CSES 4 | */ 5 | struct lca_rmq { 6 | using pll = pair; 7 | vector> T; 8 | vector linear; 9 | vector in, out, depth; 10 | ll t = 0, n; 11 | static pll _min(pll a, pll b) { return min(a, b); } 12 | sparse_table st; 13 | lca_rmq(){} 14 | lca_rmq(vector> &T, ll rooted = 0): n(T.size()) { 15 | in = out = depth = vector(n, -1); 16 | linear.resize(2*n); 17 | auto dfs = [&](int u, int d, auto&&dfs) -> void { 18 | linear[t] = {d, u}, in[u] = t++, depth[u] = d; 19 | for (int v : T[u]) { 20 | if (in[v] != -1) continue; 21 | dfs(v, d+1, dfs); 22 | linear[t++] = {d, u}; 23 | } 24 | out[u] = t; 25 | }; 26 | dfs(rooted, 0, dfs); 27 | st = sparse_table(linear); 28 | } 29 | ll query(int u, int v) { 30 | tie(u, v) = {in[u], in[v]}; 31 | return st.query(min(u, v), max(u, v)).second; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /content/maths/lagrange-point.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Using points evaluated at 0,1,..n from f(n), interpolates f(x). 3 | Time complexity O(k), where k is the amount of points 4 | *Status:* Tested on codeforces 5 | */ 6 | ll lagrange_point(vector & p, ll x){ 7 | int n = p.size(); 8 | if (x < n) return p[x]; 9 | vector pref(n+1,1), suff(n+1,1); 10 | for (int i = 1; i <= n; i++) pref[i] = (pref[i-1]*(x-(i-1)))%mod; 11 | for (int i = n-1; i >= 0; i--) suff[i] = (suff[i+1]*(x-i))%mod; 12 | vector ifact(n); 13 | ll fact = 1; 14 | for (ll i = 1; i < n; i++) fact = (fact*i)%mod; 15 | ifact[n-1] = binpow(fact,mod-2); 16 | for (ll i = n-2; i >= 0; i--) ifact[i] = (ifact[i+1]*(i+1))%mod; 17 | ll res = 0; 18 | for (int i = 1; i <= n; i++){ 19 | ll val = (pref[i-1]*suff[i])%mod; 20 | ll temp = (((n-i)&1)?mod-1:1); 21 | val = (val*temp)%mod; 22 | val = (val*ifact[i-1])%mod; 23 | val = (val*ifact[n-i])%mod; 24 | val = (val*p[i-1])%mod; 25 | res = (res+val)%mod; 26 | } 27 | if (res < 0) res += mod; 28 | return res; 29 | } -------------------------------------------------------------------------------- /lib/hash.typ: -------------------------------------------------------------------------------- 1 | #let lib = plugin("hash.wasm") 2 | 3 | /// Hashes the given data with the given digest. 4 | /// 5 | /// Arguments: 6 | /// - digest: The digest to use for hashing. Must be one of 7 | /// "blake2", "blake2s", "md5", "sha1", "sha224", 8 | /// "sha256", "sha384", "sha512", or "sha3". 9 | /// - data: The data to hash. Must be of type array, bytes, or string. 10 | /// 11 | /// Returns: The hashed data as bytes. 12 | #let hash(digest, data) = lib.hash(bytes(digest), bytes(data)) 13 | 14 | /// Converts a byte array to a hexadecimal string. 15 | /// 16 | /// Arguments: 17 | /// - bytes: The bytes to convert. 18 | /// 19 | /// Returns: The hexadecimal string. 20 | #let hex(bytes) = for byte in array(bytes) { 21 | if byte < 16 { "0" } 22 | str(int(byte), base: 16) 23 | } 24 | 25 | #let blake2 = hash.with("blake2") 26 | #let blake2s = hash.with("blake2s") 27 | #let md5 = hash.with("md5") 28 | #let sha1 = hash.with("sha1") 29 | #let sha224 = hash.with("sha224") 30 | #let sha256 = hash.with("sha256") 31 | #let sha384 = hash.with("sha384") 32 | #let sha512 = hash.with("sha512") 33 | #let sha3 = hash.with("sha3") -------------------------------------------------------------------------------- /content/graphs/4-cycle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Given a simple undirected graph with n nodes and m edges with no self loops or multiple edges find the number of 4 length cycles. 3 | Two cycles are different if their edge collections are different. Runs on $O(m sqrt(m))$ where $m$ is the number of edges. 4 | *Status:* Tested on Codeforces 5 | */ 6 | ll count_cycle_4(const vector>& g) { 7 | ll n = g.size(), w = 0; 8 | vector val(n, 0), deg(n); 9 | vector> G(n); 10 | 11 | for (ll i = 0; i < n; i++) deg[i] = g[i].size(); 12 | for (ll i = 0; i < n; i++) { 13 | for (auto e : g[i]) { 14 | if (e < i) continue; 15 | if (deg[i] <= deg[e]) G[i].push_back(e); 16 | else G[e].push_back(i); 17 | } 18 | } 19 | for (ll i = 0; i < n; i++) { 20 | for (auto u : g[i]) { 21 | for (auto v : G[u]) { 22 | if (deg[v] > deg[i] || (deg[v] == deg[i] && v > i)) 23 | w += val[v]++; 24 | } 25 | } 26 | for (auto u : g[i]) { 27 | for (auto v : G[u]) { 28 | val[v] = 0; 29 | } 30 | } 31 | } 32 | return w; 33 | } -------------------------------------------------------------------------------- /content/graphs/bellman-ford.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Calculates shortest paths from $s$ in a graph that might have negative edge weights. 3 | *Status:* Tested on CSES 4 | */ 5 | struct BellmanFord { 6 | struct Edge { int from, to; ll weight; }; 7 | int n, last_updated = -1; const ll INF = 1e18; 8 | vector p; vector dist; 9 | BellmanFord(vector &G, int s, int _n) { 10 | n = _n; dist.assign(n+1,INF); 11 | p.assign(n+1,-1); dist[s] = 0; 12 | for (int i = 1; i <= n; i++) { 13 | last_updated = -1; 14 | for (Edge &e : G) 15 | if (dist[e.from] + e.weight < dist[e.to]) { 16 | dist[e.to] = dist[e.from] + e.weight; 17 | p[e.to] = e.from; last_updated = e.to; 18 | } 19 | } 20 | } 21 | bool getCycle(vector &cycle) { 22 | if (last_updated == -1) return false; 23 | for (int i = 0; i < n-1; i++) 24 | last_updated = p[last_updated]; 25 | for (int x = last_updated ;; x=p[x]) { 26 | cycle.push_back(x); 27 | if (x == last_updated and cycle.size() > 1) break; 28 | } 29 | reverse(cycle.begin(), cycle.end()); 30 | return true; 31 | } 32 | }; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Sebastián Torrealba 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /content/data-structures/union-find-rollback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Same utility of normal union-find, but you can rollback the last union. Runs on $O( alpha (n) ) $ 3 | *Status:* Highly tested 4 | */ 5 | struct op{ 6 | int v,u; 7 | int v_value,u_value; 8 | op(int _v,int _v_value,int _u,int _u_value): v(_v),v_value(_v_value),u(_u),u_value(_u_value) {} 9 | }; 10 | struct union_find_rb { 11 | vector e; 12 | stack ops; 13 | int comps; 14 | union_find_rb(){} 15 | union_find_rb(int n): comps(n) {e.assign(n, -1);} 16 | int findSet (int x) { 17 | return (e[x] < 0 ? x : findSet(e[x])); 18 | } 19 | bool sameSet (int x, int y) { return findSet(x) == findSet(y); } 20 | int size (int x) { return -e[findSet(x)]; } 21 | bool unionSet (int x, int y) { 22 | x = findSet(x), y = findSet(y); 23 | if (x == y) return 0; 24 | if (e[x] > e[y]) swap(x, y); 25 | ops.push(op(x,e[x],y,e[y])); comps--; 26 | e[x] += e[y], e[y] = x; 27 | return 1; 28 | } 29 | void rb(){ 30 | if(ops.empty()) return; 31 | op last = ops.top(); ops.pop(); 32 | e[last.v] = last.v_value; 33 | e[last.u] = last.u_value; 34 | comps++; 35 | } 36 | }; -------------------------------------------------------------------------------- /content/strings/z.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Z-algorithm for string matching, finds all occurrences in $O(n+m)$ 3 | *Status:* Tested 4 | */ 5 | struct Z { 6 | int n, m; 7 | vector z; 8 | Z(string s) { 9 | n = s.size(); 10 | z.assign(n, 0); 11 | int l = 0, r = 0; 12 | for (int i = 1; i < n; i++) { 13 | if (i <= r) 14 | z[i] = min(r - i + 1, z[i - l]); 15 | while (i + z[i] < n && s[z[i]] == s[i + z[i]]) 16 | ++z[i]; 17 | if (i + z[i] - 1 > r) 18 | l = i, r = i + z[i] - 1; 19 | } 20 | } 21 | Z(string p, string t) { 22 | string s = p + "#" + t; 23 | n = p.size(); 24 | m = t.size(); 25 | z.assign(n + m + 1, 0); 26 | int l = 0, r = 0; 27 | for (int i = 1; i < n + m + 1; i++) { 28 | if (i <= r) 29 | z[i] = min(r - i + 1, z[i - l]); 30 | while (i + z[i] < n + m + 1 && s[z[i]] == s[i + z[i]]) 31 | ++z[i]; 32 | if (i + z[i] - 1 > r) 33 | l = i, r = i + z[i] - 1; 34 | } 35 | } 36 | void p_in_t(vector& ans) { 37 | for (int i = n + 1; i < n + m + 1; i++) { 38 | if (z[i] == n) 39 | ans.push_back(i - n - 1); 40 | } 41 | } 42 | }; -------------------------------------------------------------------------------- /content/graphs/3-cycle.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Given a simple undirected graph with n nodes and m edges with no self loops or multiple edges find the number of 3 length cycles. 3 | Two cycles are different if their edge collections are different. Runs on $O(m sqrt(m))$ where $m$ is the number of edges. 4 | *Status:* Not tested 5 | */ 6 | ll count_cycle_3(const vector>& g) { 7 | ll n = g.size(), w = 0; 8 | vector val(n, 0), deg(n); 9 | vector> G(n); 10 | 11 | for (ll i = 0; i < n; i++) deg[i] = g[i].size(); 12 | for (ll i = 0; i < n; i++) { 13 | for (auto e : g[i]) { 14 | if (e < i) continue; 15 | if (deg[i] <= deg[e]) G[i].push_back(e); 16 | else G[e].push_back(i); 17 | } 18 | } 19 | for (ll i = 0; i < n; i++) { 20 | for (auto u : G[i]) val[u] = i; 21 | for (auto e : g[i]) { 22 | if (e < i) continue; 23 | // x = deg[i] + deg[e] + 3; 24 | for (auto v : G[e]) 25 | if (val == i) { 26 | w++; 27 | // w+=x + deg[v] - 2; 28 | // For number of 3-cycles with or without an extra edge 29 | } 30 | } 31 | } 32 | return w; 33 | } -------------------------------------------------------------------------------- /content/algorithms/mo-update.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Allow us to answer queries and updates offline with block decomposition in $O(q dot n^(2/3) )$ 3 | *Status:* Not tested 4 | */ 5 | struct query { 6 | int l,r,t,i; 7 | }; 8 | template 9 | struct mo_update { 10 | vector ans; 11 | mo_update(vector &v, vector &queries, vector> & updates, T2 & ds) { 12 | ds.init(v,updates); 13 | int block_sz = cbrtl(2*v.size()*v.size()); 14 | ans.assign(queries.size(),-1); 15 | sort(queries.begin(), queries.end(), [&](auto a, auto b){ 16 | if (a.l/block_sz == b.l/block_sz){ 17 | if (a.r/block_sz == b.r/block_sz) return a.t < b.t; 18 | return a.r/block_sz < b.r/block_sz; 19 | } 20 | return a.l/block_sz < b.l/block_sz; 21 | }); 22 | int l = 0, r = -1; 23 | for (query q : queries) { 24 | while (ds.t < q.t) ds.update(l,r); 25 | while (ds.t > q.t) ds.rollback(l,r); 26 | while (l > q.l) ds.add(--l); 27 | while (r < q.r) ds.add(++r); 28 | while (l < q.l) ds.remove(l++); 29 | while (r > q.r) ds.remove(r--); 30 | ans[q.i] = ds.answer(q); 31 | } 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /content/dynamic-programming/li-chao-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Dynamically insert lines of the form y = a*x + b and query for the minimum value at any x in a fixed interval [L, R]. 3 | *Status:* Partially tested 4 | */ 5 | struct Line{ 6 | ll a,b; // ax + b 7 | Line(ll _a, ll _b) : a(_a), b(_b) {}; 8 | ll eval(ll x){ return a*x + b;} 9 | }; 10 | 11 | struct li_chao{ 12 | const ll INF = 1e18; 13 | ll L,R; 14 | vector st; 15 | li_chao(ll l,ll r){ 16 | L = l, R = r+1; 17 | st = vector(4*(r - l + 1),Line(0,INF)); 18 | }; 19 | void add(Line nw, ll v, ll l, ll r){ 20 | ll m = (l+r)/2; 21 | bool lc = nw.eval(l) < st[v].eval(l); 22 | bool mc = nw.eval(m) < st[v].eval(m); 23 | if(mc) swap(nw,st[v]); 24 | if(r - l == 1) return; 25 | if(lc != mc) add(nw,2*v,l,m); 26 | else add(nw,2*v + 1,m,r); 27 | } 28 | ll get(ll x, ll v, ll l, ll r){ 29 | ll m = (l+r)/2; 30 | if(r - l == 1) return st[v].eval(x); 31 | if(x < m) return min(st[v].eval(x),get(x,2*v,l,m)); 32 | return min(st[v].eval(x),get(x,2*v+1,m,r)); 33 | } 34 | 35 | void add(ll a, ll b){add(Line(a,b),1,L,R);}; 36 | ll get(ll x){return get(x,1,L,R);}; 37 | }; 38 | -------------------------------------------------------------------------------- /content/strings/manacher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Find palindromes centered at $i$ in $O(n)$ 3 | *Status:* Tested on CSES 4 | */ 5 | template 6 | struct manacher { 7 | vector odd, even; 8 | T s; int n; 9 | manacher(T &s): s(s), n(s.size()) { 10 | odd.resize(n); 11 | even.resize(n); 12 | for (int i = 0, l = 0, r = -1; i < n; i++) { 13 | int k = (i > r) ? 1 : min(odd[l+r-i], r-i+1); 14 | while (0 <= i-k and i+k < n and s[i-k] == s[i+k]) k++; 15 | odd[i] = k--; 16 | if (i+k > r) l = i-k, r = i+k; 17 | } 18 | for (int i = 0, l = 0, r = -1; i < n; i++) { 19 | int k = (i > r) ? 0 : min(even[l + r - i + 1], r - i + 1); 20 | while (0 <= i - k - 1 and i + k < n && s[i - k - 1] == s[i + k]) k++; 21 | even[i] = k--; 22 | if (i + k > r) l = i - k - 1, r = i + k; 23 | } 24 | } 25 | // Returns the longest palindrome centered at i 26 | pair get(int i) { 27 | int o = 2 * odd[i] - 1; // Normally centered (Is odd size) 28 | int e = 2 * even[i]; // Centered to the right 29 | if (o >= e) 30 | return {i - odd[i] + 1, i + odd[i] - 1}; 31 | return {i - even[i], i + even[i] - 1}; 32 | } 33 | }; -------------------------------------------------------------------------------- /content/data-structures/sqrt-decomposition.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries, build $O(n)$, query and update $O(sqrt(n))$, positions [0, n - 1] 3 | *Status:* Tested on CF 4 | */ 5 | template 6 | struct sqrt_decomp { 7 | int n,sq; 8 | vector st,bl; 9 | sqrt_decomp(vector & a){ 10 | n = a.size(); st.resize(n); 11 | sq = sqrtl(n); bl.resize((n+sq-1)/sq); 12 | for (int i = 0; i < n; i++){ 13 | st[i] = a[i]; 14 | bl[i/sq] = ((i%sq == 0)?st[i]:merge(bl[i/sq],st[i])); 15 | } 16 | } 17 | void update(int pos, T val) { 18 | st[pos] = val; 19 | int block = pos/sq, lb = block*sq, rb = min(block*sq+sq-1,n-1); 20 | T vl; 21 | for (int i = lb; i <= rb; i++) 22 | vl = ((i == lb)?st[i]:merge(vl,st[i])); 23 | bl[block] = vl; 24 | } 25 | int query(int l, int r){ 26 | T res; bool hasR = 0; 27 | for (int i = l/sq; i <= r/sq; i++){ 28 | int lb = i*sq, rb = i*sq+sq-1; 29 | if (l <= lb && rb <= r){ 30 | res = (hasR?merge(res,bl[i]):bl[i]), hasR = 1; 31 | continue; 32 | } 33 | for (int j = max(l,lb); j <= min(rb,r); j++) 34 | res = (hasR?merge(res,st[j]):st[j]), hasR = 1; 35 | } 36 | return res; 37 | } 38 | }; 39 | -------------------------------------------------------------------------------- /content/strings/trie.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Trie (prefix tree) for string storage and prefix queries 3 | *Status:* Tested 4 | */ 5 | struct trie { 6 | vector > tree; 7 | vector counts; 8 | trie() { 9 | tree.push_back(vector(26, -1)); 10 | counts.push_back(0); 11 | }; 12 | void insert(string &s) { 13 | ll i = 0, u = 0; 14 | while(i < s.size()){ 15 | char c = s[i]; 16 | if (tree[u][c - 'a'] == -1){ 17 | ll pos = tree.size(); 18 | tree.push_back(vector(26, -1)); 19 | counts.push_back(0); 20 | tree[u][c - 'a'] = pos; 21 | } 22 | i++; 23 | u = tree[u][c - 'a']; 24 | } 25 | counts[u]++; // count final character 26 | } 27 | ll search(string &s){ 28 | ll i = 0,u = 0; 29 | ll count_ends = 0; 30 | while(i < s.size()){ 31 | char c = s[i]; 32 | if (tree[u][c - 'a'] != -1){ 33 | //If you need to know how many trailing characters it goes through, uncomment. 34 | //count_ends += counts[u]; 35 | u = tree[u][c - 'a']; 36 | i++; 37 | }else break; 38 | } 39 | if(i == s.size()) count_ends += counts[u]; 40 | return count_ends; 41 | } 42 | }; 43 | -------------------------------------------------------------------------------- /content/maths/xor-basis.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Calculate the xor basis of a set of numbers. 3 | *Complexity:* 4 | - Insertion: O(d) 5 | - Query if a number can be formed: O(d) 6 | - Get maximum xor subset: O(d) 7 | - Merging two bases: O(d^2) 8 | *Status:* Partially tested 9 | */ 10 | 11 | struct xor_basis { 12 | int d, sz; 13 | vector basis; 14 | xor_basis(int _d): d(_d), sz(0), basis(_d, 0) {} 15 | bool insert(long long mask) { 16 | for (int i = d - 1; i >= 0; --i) { 17 | if ((mask & (1LL << i)) == 0) continue; 18 | if (!basis[i]) { 19 | basis[i] = mask; 20 | ++sz; 21 | return true; 22 | } 23 | mask ^= basis[i]; 24 | } 25 | return false; 26 | } 27 | bool can_make(long long x){ 28 | for (int i = d - 1; i >= 0; --i) { 29 | if ((x & (1LL << i)) == 0) continue; 30 | if (!basis[i]) return false; 31 | x ^= basis[i]; 32 | } 33 | return x == 0; 34 | } 35 | long long get_max(){ 36 | long long res = 0; 37 | for (int i = d - 1; i >= 0; --i) 38 | if ((res ^ basis[i]) > res) res ^= basis[i]; 39 | return res; 40 | } 41 | void merge(const xor_basis &o) { 42 | for (long long v : o.basis) 43 | if (v) insert(v); 44 | } 45 | }; -------------------------------------------------------------------------------- /content/data-structures/min-deque.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the minumum element of the deque, runs on $O(1)$ per operation amortized. Can be modified to get the maximum just changing the function 3 | *Status:* Not tested 4 | */ 5 | template 6 | struct min_deque { 7 | min_stack l, r, t; 8 | void rebalance() { 9 | bool f = false; 10 | if (r.empty()) {f = true; l.swap(r);} 11 | int sz = r.size() / 2; 12 | while (sz--) {t.push(r.top()); r.pop();} 13 | while (!r.empty()) {l.push(r.top()); r.pop();} 14 | while (!t.empty()) {r.push(t.top()); t.pop();} 15 | if (f) l.swap(r); 16 | } 17 | int getmin() { 18 | if (l.empty()) return r.getmin(); 19 | if (r.empty()) return l.getmin(); 20 | return min(l.getmin(), r.getmin()); 21 | } 22 | bool empty() {return l.empty() and r.empty();} 23 | int size() {return l.size() + r.size();} 24 | void push_front(int x) {l.push(x);} 25 | void push_back(int x) {r.push(x);} 26 | void pop_front() {if (l.empty()) rebalance(); l.pop();} 27 | void pop_back() {if (r.empty()) rebalance(); r.pop();} 28 | int front() {if (l.empty()) rebalance(); return l.top();} 29 | int back() {if (r.empty()) rebalance(); return r.top();} 30 | void swap(min_deque &x) {l.swap(x.l); r.swap(x.r);} 31 | }; 32 | -------------------------------------------------------------------------------- /content/data-structures/disjoint-sparse-table.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries, precomputed $O(n log n)$, query $O(1)$. 3 | - Only needs associativity 4 | - Does not allow updates 5 | *Status:* Tested on CSES/Codeforces 6 | */ 7 | template 8 | struct disjoint_sparse_table{ 9 | static const int MAXLOG = 20; 10 | vector dp[MAXLOG]; vector has[MAXLOG]; 11 | disjoint_sparse_table() {} 12 | disjoint_sparse_table(vector &ar){ 13 | int i, c, h, l, n = (int)ar.size(); 14 | for (h = 0; h <= __lg(n); h++){ 15 | dp[h].resize(n + 1), has[h].resize(n+1); 16 | for (c = l = 1 << h; c < n + l; c += (l << 1)){ 17 | for (i = c + 1; i <= min(n, c + l); i++) { 18 | if (!has[h][i-1]) dp[h][i] = ar[i-1]; 19 | else dp[h][i] = m_(dp[h][i - 1], ar[i-1]); 20 | has[h][i] = 1; 21 | } 22 | for (i = min(n, c) - 1; i >= c - l; i--) { 23 | if (!has[h][i+1]) dp[h][i] = ar[i]; 24 | else dp[h][i] = m_(ar[i], dp[h][i+1]); 25 | has[h][i] = 1; 26 | } 27 | } 28 | } 29 | } 30 | T query(int l, int r){ 31 | int h = __lg(l ^ (r + 1)); 32 | if (!has[h][l]) return dp[h][r+1]; 33 | if (!has[h][r+1]) return dp[h][l]; 34 | return m_(dp[h][l], dp[h][r + 1]); 35 | } 36 | }; 37 | -------------------------------------------------------------------------------- /content/dynamic-programming/line-container.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Dynamically insert a*x + b lines and query for maximum at any x and operations have complexity O(log N) 3 | *Status:* Tested on CSES 4 | */ 5 | struct Line { 6 | mutable int a, b, c; 7 | bool operator<(Line r) const { return a < r.a; } 8 | bool operator<(int x) const { return c < x; } 9 | }; 10 | struct LineContainer : multiset> { 11 | int div(int a, int b) { 12 | return a / b - ((a ^ b) < 0 && a % b); 13 | } 14 | bool isect(iterator x, iterator y) { 15 | if (y == end()) return x->c = INF, 0; 16 | if (x->a == y->a) x->c = x->b > y->b ? INF : -INF; 17 | else x->c = div(y->b - x->b, x->a - y->a); 18 | return x->c >= y->c; 19 | } 20 | void add(int a, int b) { 21 | // a *= -1, b *= -1 // for min 22 | auto z = insert({a, b, 0}), y = z++, x = y; 23 | while (isect(y, z)) z = erase(z); 24 | if (x != begin() && isect(--x, y)) isect(x, y = erase(y)); 25 | while ((y = x) != begin() && (--x)->c >= y->c) isect(x, erase(y)); 26 | } 27 | int query(int x) { 28 | if (empty()) return -INF; // INF for min 29 | auto l = *lower_bound(x); 30 | return l.a * x + l.b; 31 | // return -l.a * x - l.b; // for min 32 | } 33 | }; -------------------------------------------------------------------------------- /content/data-structures/query-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Allow us to solve dynamic conectivity offline 3 | *Status:* Tested 4 | */ 5 | struct query{ 6 | int v,u; 7 | bool status; 8 | query(int _v,int _u) : v(_v),u(_u) {}; 9 | }; 10 | struct query_tree{ 11 | vector> tree; 12 | int size; 13 | // rollback structure 14 | UnionFindRB uf; 15 | query_tree(int _size,int n) : size(_size) {uf = UnionFindRB(n); tree.resize(4*_size + 4);} 16 | void addTree(int v,int l,int r,int ul,int ur, query& q){ 17 | if(ul > ur) return; 18 | if(l == ul && ur == r){tree[v].push_back(q); return; } 19 | int mid = (l + r)/2; 20 | addTree(2*v,l,mid,ul,min(ur,mid),q); 21 | addTree(2*v + 1,mid + 1,r,max(ul,mid + 1),ur,q); 22 | } 23 | void add(query q,int l,int r){addTree(1,0,size - 1,l,r,q);} 24 | void dfs(int v,int l,int r,vector &ans){ 25 | // change in data structure 26 | for(query &q: tree[v]) q.status = uf.unionSet(q.v,q.u); 27 | if(l == r) ans[l] = uf.comps; 28 | else{ 29 | int mid = (l + r)/2; 30 | dfs(2*v,l,mid,ans); 31 | dfs(2*v + 1,mid + 1,r,ans); 32 | } 33 | // rollback in data structure 34 | for(query q: tree[v]) if(q.status) uf.rb(); 35 | } 36 | vector getAns(){ 37 | vector ans(size); 38 | dfs(1,0,size - 1,ans); 39 | return ans; 40 | } 41 | }; -------------------------------------------------------------------------------- /content/geometry/convex-hull.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Get the convex hull of the cloud of points, allow collinear points if is needed 3 | *Status:* Highly tested 4 | */ 5 | template 6 | vector> convexHull(vector> cloud, bool ac = 0) { 7 | int n = cloud.size(), k = 0; 8 | sort(cloud.begin(), cloud.end(), [](Point2D &a, Point2D &b) { 9 | return a.x < b.x or (a.x == b.x and a.y < b.y); 10 | }); 11 | if (n <= 2) return cloud; 12 | bool allCollinear = true; 13 | for (int i = 2; i < n; ++i) { 14 | if (((cloud[1] - cloud[0]) ^ (cloud[i] - cloud[0])) != 0) { 15 | allCollinear = false; break; 16 | } 17 | } 18 | if (allCollinear) return ac ? cloud : vector>{cloud[0], cloud.back()}; 19 | vector> ch(2 * n); 20 | auto process = [&](int st, int end, int stp, int t, auto cmp) { 21 | for (int i = st; i != end; i += stp) { 22 | while (k >= t and cmp(ch[k - 1], ch[k - 2], cloud[i])) k--; 23 | ch[k++] = cloud[i]; 24 | } 25 | }; 26 | process(0, n, 1, 2, [&](auto a, auto b, auto c) { 27 | return ((a - b) ^ (c - b)) < (ac ? 0 : 1); 28 | }); 29 | process(n - 2, -1, -1, k + 1, [&](auto a, auto b, auto c) { 30 | return ((a - b) ^ (c - b)) < (ac ? 0 : 1); 31 | }); 32 | ch.resize(k - 1); 33 | return ch; 34 | } 35 | -------------------------------------------------------------------------------- /content/maths/gauss.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Matrix elimination, runs on $O(n^3)$ 3 | *Status:* Not tested 4 | */ 5 | const double EPS = 1e-18; 6 | const int INF = 2; // it doesn't actually have to be infinity or a big number 7 | const int MOD = 1e9+7; 8 | int gauss(vector> a, vector & ans) { 9 | int n = (int) a.size(); 10 | int m = (int) a[0].size() - 1; 11 | 12 | vector where(m, -1); 13 | for (int col = 0, row = 0; col < m && row < n; ++col) { 14 | int sel = row; 15 | for (int i = row; i < n; ++i) 16 | if (abs(a[i][col]) > abs(a[sel][col])) 17 | sel = i; 18 | if (!a[sel][col]) 19 | continue; 20 | for (int i = col; i <= m; ++i) 21 | swap(a[sel][i], a[row][i]); 22 | where[col] = row; 23 | 24 | for (int i = 0; i < n; ++i) 25 | if (i != row) { 26 | ll c = ((ll) a[i][col] * binpow(round(a[row][col]), MOD - 2, MOD)) % MOD; 27 | for (int j = col; j <= m; ++j) 28 | a[i][j] = ((a[i][j] - a[row][j] * c) % MOD + MOD) % MOD; 29 | } 30 | ++row; 31 | } 32 | 33 | ans.assign(m, 0); 34 | for (int i = 0; i < m; ++i) 35 | if (where[i] != -1) 36 | ans[i] = ((ll) a[where[i]][m] * binpow(round(a[where[i]][i]), MOD - 2, MOD)) % MOD; 37 | 38 | for (int i = 0; i < m; ++i) 39 | if (where[i] == -1) 40 | return INF; 41 | return 1; 42 | } 43 | -------------------------------------------------------------------------------- /content/graphs/hungarian.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Solves assignament problem in $O(n^3)$. If the matrix is rectangular in $O(n^2 m)$, where $n <= m$ 3 | *Status:* Tested 4 | */ 5 | void Hungarian(vector> &A, vector> &result, int &C, const int INF = 1e6 + 1) { 6 | int n = A.size() - 1, m = A[0].size() - 1; 7 | vector minv(m + 1), u(n + 1), v(m + 1), p(m + 1), way(m + 1); 8 | vector used(m + 1); 9 | for (int i = 1; i <= n; ++i) { 10 | p[0] = i; int j0 = 0; 11 | for (int j = 0; j <= m; ++j) 12 | minv[j] = INF; 13 | for (int j = 0; j <= m; ++j) 14 | used[j] = false; 15 | do { 16 | used[j0] = true; 17 | int i0 = p[j0], delta = INF, j1; 18 | for (int j = 1; j <= m; ++j) 19 | if (!used[j]) { 20 | int cur = A[i0][j] - u[i0] - v[j]; 21 | if (cur < minv[j]) minv[j] = cur, way[j] = j0; 22 | if (minv[j] < delta) delta = minv[j], j1 = j; 23 | } 24 | for (int j = 0; j <= m; ++j) { 25 | if (used[j]) u[p[j]] += delta, v[j] -= delta; 26 | else minv[j] -= delta; 27 | } 28 | j0 = j1; 29 | } while (p[j0] != 0); 30 | do { 31 | int j1 = way[j0]; 32 | p[j0] = p[j1]; 33 | j0 = j1; 34 | } while(j0); 35 | } 36 | for (int i = 1; i <= m; ++i) 37 | result.push_back(make_pair(p[i], i)); 38 | C = -v[0]; 39 | } -------------------------------------------------------------------------------- /content/data-structures/line-container.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Line container for convex hull trick optimization in DP 3 | *Status:* Tested 4 | */ 5 | struct Line { 6 | mutable ll a, b, c; 7 | bool operator<(Line r) const { 8 | return a < r.a; 9 | } 10 | bool operator<(ll x) const { 11 | return c < x; 12 | } 13 | }; 14 | // dynamically insert `a*x + b` lines and query for maximum 15 | // at any x all operations have complexity O(log N) 16 | struct LineContainer: multiset < Line, less < >> { 17 | ll div(ll a, ll b) { 18 | return a / b - ((a ^ b) < 0 && a % b); 19 | } 20 | bool isect(iterator x, iterator y) { 21 | if (y == end()) return x -> c = INF, 0; 22 | if (x -> a == y -> a) x -> c = x -> b > y -> b ? INF : -INF; 23 | else x -> c = div(y -> b - x -> b, x -> a - y -> a); 24 | return x -> c >= y -> c; 25 | } 26 | 27 | void add(ll a, ll b) { 28 | // a *= -1, b *= -1 // for min 29 | auto z = insert({ 30 | a, 31 | b, 32 | 0 33 | }), y = z++, x = y; 34 | while (isect(y, z)) z = erase(z); 35 | if (x != begin() && isect(--x, y)) isect(x, y = erase(y)); 36 | while ((y = x) != begin() && (--x) -> c >= y -> c) isect(x, erase(y)); 37 | } 38 | 39 | ll query(ll x) { 40 | if (empty()) return -INF; // INF for min 41 | auto l = * lower_bound(x); 42 | return l.a * x + l.b; 43 | // return -l.a * x - l.b; // for min 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /content/geometry/halfplane-intersection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Halfplane intersection 3 | *Status:* Partially tested 4 | */ 5 | vector> hp_intersect(vector &H) { 6 | Point2D box[4] = {{inf, inf}, {-inf, inf}, {-inf, -inf}, {inf, -inf}}; 7 | for (int i = 0; i < 4; i++) { 8 | Halfplane aux(box[i], box[(i + 1) % 4]); 9 | H.push_back(aux); 10 | } 11 | sort(H.begin(), H.end()); 12 | deque dq; 13 | int len = 0; 14 | for (int i = 0; i < H.size(); i++) { 15 | while (len > 1 && H[i].out(inter(dq[len - 1], dq[len - 2]))) 16 | dq.pop_back(), --len; 17 | while (len > 1 && H[i].out(inter(dq[0], dq[1]))) 18 | dq.pop_front(), --len; 19 | if (len > 0 && fabsl((H[i].pq ^ dq[len - 1].pq)) < eps) { 20 | if ((H[i].pq | dq[len - 1].pq) < 0.0) 21 | return vector>(); 22 | if (H[i].out(dq[len - 1].p)) 23 | dq.pop_back(), --len; 24 | else 25 | continue; 26 | } 27 | dq.push_back(H[i]), ++len; 28 | } 29 | while (len > 2 && dq[0].out(inter(dq[len - 1], dq[len - 2]))) 30 | dq.pop_back(), --len; 31 | while (len > 2 && dq[len - 1].out(inter(dq[0], dq[1]))) 32 | dq.pop_front(), --len; 33 | if (len < 3) 34 | return vector>(); 35 | vector> ret(len); 36 | for (int i = 0; i + 1 < len; i++) 37 | ret[i] = inter(dq[i], dq[i + 1]); 38 | ret.back() = inter(dq[len - 1], dq[0]); 39 | return ret; 40 | } 41 | -------------------------------------------------------------------------------- /content/graphs/lca.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Computes lowest common ancestor, precomputed in $O(V log V)$, $O(log V)$ per query, uses binary lifting and works for directed and undirected graphs. 3 | *Status:* Tested 4 | */ 5 | struct LCA { 6 | vector> T, parent; 7 | vector depth, vis; 8 | int LOGN, V; 9 | // If WA, bigger logn? 10 | LCA(vector> &T, int logn = 20): T(T), LOGN(logn), vis(T.size()) { 11 | parent.assign(T.size()+1, vector(LOGN, 0)); 12 | depth.assign(T.size()+1, 0); 13 | // If is forest 14 | //for (int u = 0; u < T.size(); u++) 15 | // if (!vis[u]) dfs(u); 16 | } 17 | void dfs(int u = 0, int p = -1) { 18 | vis[u] = true; 19 | for (int v : T[u]) { 20 | if (p != v) { 21 | depth[v] = depth[u] + 1; 22 | parent[v][0] = u; 23 | for (int j = 1; j < LOGN; j++) 24 | parent[v][j] = parent[parent[v][j-1]][j-1]; 25 | dfs(v, u); 26 | } 27 | } 28 | } 29 | int query(int u, int v) { 30 | if (depth[u] < depth[v]) swap(u, v); 31 | int k = depth[u]-depth[v]; 32 | for (int j = LOGN - 1; j >= 0; j--) 33 | if (k & (1 << j)) 34 | u = parent[u][j]; 35 | if (u == v) 36 | return u; 37 | for (int j = LOGN - 1; j >= 0; j--) { 38 | if (parent[u][j] != parent[v][j]) { 39 | u = parent[u][j]; 40 | v = parent[v][j]; 41 | } 42 | } 43 | return parent[u][0]; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /content/graphs/dinic.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Pablo Messina 3 | *Source:* https://github.com/PabloMessina/Competitive-Programming-Material 4 | *Description:* Flow algorithm with complexity $O (|E| dot |V|^2)$ 5 | *Status:* Not tested 6 | */ 7 | struct Dinic { 8 | struct Edge { ll to, rev; ll f, c; }; 9 | ll n, t_; vector> G; 10 | vector D, q, W; 11 | bool bfs(ll s, ll t) { 12 | W.assign(n, 0); D.assign(n, -1); D[s] = 0; 13 | ll f = 0, l = 0; q[l++] = s; 14 | while (f < l) { 15 | ll u = q[f++]; 16 | for (const Edge &e : G[u]) if (D[e.to] == -1 && e.f < e.c) 17 | D[e.to] = D[u] + 1, q[l++] = e.to; 18 | } 19 | return D[t] != -1; 20 | } 21 | ll dfs(ll u, ll f) { 22 | if (u == t_) return f; 23 | for (ll &i = W[u]; i < (ll)G[u].size(); ++i) { 24 | Edge &e = G[u][i]; ll v = e.to; 25 | if (e.c <= e.f || D[v] != D[u] + 1) continue; 26 | ll df = dfs(v, min(f, e.c - e.f)); 27 | if (df > 0) { e.f += df, G[v][e.rev].f -= df; return df; } 28 | } 29 | return 0; 30 | } 31 | Dinic(ll N) : n(N), G(N), D(N), q(N) {} 32 | void add_edge(ll u, ll v, ll cap) { 33 | G[u].push_back({v, (ll)G[v].size(), 0, cap}); 34 | G[v].push_back({u, (ll)G[u].size() - 1, 0, 0}); // Use cap instead of 0 if bidirectional 35 | } 36 | ll max_flow(ll s, ll t) { 37 | t_ = t; ll ans = 0; 38 | while (bfs(s, t)) while (ll dl = dfs(s, LLONG_MAX)) ans += dl; 39 | return ans; 40 | } 41 | }; -------------------------------------------------------------------------------- /content/maths/fwht.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* 3 | *Description:* Computes XOR, OR and AND convolution of two arrays in $O(n log n)$. 4 | op = 0 -> OR, op = 1 -> AND, op = 2 -> XOR, mxn and n must be powers of two. 5 | *Status:* Tested on CSES 6 | */ 7 | const int mod = 1e9+7, mxn = (1<<20), op = 2; 8 | const int inv2 = (mod+1) >> 1; 9 | struct fwht { 10 | int P1[mxn], P2[mxn]; 11 | void wt(int *a, int n){ 12 | if (n == 0) return; 13 | int m = n/2; 14 | wt(a,m); wt(a+m,m); 15 | for (int i = 0; i < m; i++){ 16 | int x = a[i], y = a[i+m]; 17 | if (op == 0) a[i] = x, a[i+m] = (x+y)%mod; 18 | if (op == 1) a[i] = (x+y)%mod, a[i+m] = y; 19 | if (op == 2) a[i] = (x+y)%mod, a[i+m] = (x-y+mod)%mod; 20 | } 21 | } 22 | void iwt(int* a, int n){ 23 | if (n == 0) return; 24 | int m = n/2; 25 | iwt(a,m); iwt(a+m,m); 26 | for (int i = 0; i < m; i++){ 27 | int x = a[i], y = a[i+m]; 28 | if (op == 0) a[i] = x, a[i+m] = (y-x+mod)%mod; 29 | if (op == 1) a[i] = (x-y+mod)%mod, a[i+m] = y; 30 | if (op == 2) a[i] = 1LL*(x+y)*inv2%mod, a[i+m] = 1LL*(x-y+mod)*inv2%mod; 31 | } 32 | } 33 | vector conv(int n, vector A, vector B) { 34 | A.resize(n); B.resize(n); 35 | for (int i = 0; i < n; i++) P1[i] = A[i]; 36 | for (int i = 0; i < n; i++) P2[i] = B[i]; 37 | wt(P1, n); wt(P2, n); 38 | for (int i = 0; i < n; i++) P1[i] = 1LL*P1[i]*P2[i]%mod; 39 | iwt(P1, n); 40 | return vector (P1, P1 + n); 41 | } 42 | } FWHT; -------------------------------------------------------------------------------- /content/strings/suffix-automaton.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Suffix automaton (DAWG) for string processing, $O(n)$ construction 3 | *Status:* Tested 4 | */ 5 | struct SuffixAutomaton { 6 | struct state { 7 | int len, link; 8 | int next[26]; 9 | state(int _len = 0, int _link = -1) : len(_len), link(_link) { 10 | memset(next, -1, sizeof(next)); 11 | } 12 | }; 13 | vector st; 14 | int last; 15 | SuffixAutomaton() {} 16 | SuffixAutomaton(const string &s) { init(s); } 17 | inline int State(int len = 0, int link = -1) { 18 | st.emplace_back(len, link); 19 | return st.size() - 1; 20 | } 21 | void init(const string &s) { 22 | st.reserve(2 * s.size()); 23 | last = State(); 24 | for (char c : s) 25 | extend(c); 26 | } 27 | void extend(char _c) { 28 | int c = _c - 'a', cur = State(st[last].len + 1), P = last; 29 | while ((P != -1) && (st[P].next[c] == -1)) { 30 | st[P].next[c] = cur; 31 | P = st[P].link; 32 | } 33 | if (P == -1) 34 | st[cur].link = 0; 35 | else { 36 | int Q = st[P].next[c]; 37 | if (st[P].len + 1 == st[Q].len) 38 | st[cur].link = Q; 39 | else { 40 | int C = State(st[P].len + 1, st[Q].link); 41 | copy(st[Q].next, st[Q].next + 26, st[C].next); 42 | while ((P != -1) && (st[P].next[c] == Q)) { 43 | st[P].next[c] = C; 44 | P = st[P].link; 45 | } 46 | st[Q].link = st[cur].link = C; 47 | } 48 | } 49 | last = cur; 50 | } 51 | }; -------------------------------------------------------------------------------- /content/strings/kmp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Find occurrences of a pattern within given text, runs in $O(n + m)$, where $n$ and $m$ are the lengths of the text and pattern respectively. 3 | *Status:* Tested on CSES 4 | */ 5 | 6 | // Memory-efficient string matching version 7 | template struct KMP { 8 | T pattern; vector lps; 9 | KMP(T &pat): pattern(pat) { 10 | lps.resize(pat.size(), 0); 11 | int len = 0, i = 1; 12 | while (i < pattern.size()) { 13 | if (pattern[i] == pattern[len]) 14 | lps[i++] = ++len; 15 | else { 16 | if (len != 0) len = lps[len - 1]; 17 | else lps[i++] = 0; 18 | } 19 | } 20 | } 21 | vector search(T &text) { 22 | vector matches; 23 | int i = 0, j = 0; 24 | while (i < text.size()) { 25 | if (pattern[j] == text[i]) { 26 | i++, j++; 27 | if (j == pattern.size()) { 28 | matches.push_back(i - j); 29 | j = lps[j - 1]; 30 | } 31 | } else { 32 | if (j != 0) j = lps[j - 1]; 33 | else i++; 34 | } 35 | } 36 | return matches; 37 | } 38 | }; 39 | 40 | // Simple version 41 | template 42 | vector prefix(T &S) { 43 | vector P(S.size()); 44 | P[0] = 0; 45 | for(int i = 1; i < S.size(); ++ i) { 46 | P[i] = P[i - 1]; 47 | while(P[i] > 0 && S[P[i]] != S[i]) 48 | P[i] = P[P[i] - 1]; 49 | if(S[P[i]] == S[i]) 50 | ++ P[i]; 51 | } 52 | return P; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /content/maths/matrix.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Carlos Lagos 3 | *Description:* Matrix operations including multiplication and binary exponentiation 4 | *Status:* Tested 5 | */ 6 | 7 | template 8 | vector> multWithoutMOD(vector> &a, vector> &b){ 9 | int n = a.size(),m = b[0].size(),l = a[0].size(); 10 | vector> ans(n,vector(m,0)); 11 | for(int i = 0; i < n; i++){ 12 | for(int j = 0; j < m; j++){ 13 | for(int k = 0; k < l; k++){ 14 | ans[i][j] += a[i][k]*b[k][j]; 15 | } 16 | } 17 | } 18 | return ans; 19 | } 20 | 21 | template 22 | vector> mult(vector> a, vector> b,long long mod){ 23 | int n = a.size(),m = b[0].size(),l = a[0].size(); 24 | vector> ans(n,vector(m,0)); 25 | for(int i = 0; i < n; i++){ 26 | for(int j = 0; j < m; j++){ 27 | for(int k = 0; k < l; k++){ 28 | T temp = (a[i][k]*b[k][j]) % mod; 29 | ans[i][j] = (ans[i][j] + temp) % mod; 30 | } 31 | } 32 | } 33 | /* 34 | for(auto &line: ans) 35 | for(T &a: line) a = (a % mod + mod) % mod; 36 | */ 37 | return ans; 38 | } 39 | 40 | vector> binpow(vector> v,ll n,long long mod){ 41 | ll dim = v.size(); vector> ans(dim,vector(dim,0)); 42 | for(ll i = 0; i < dim; i++) ans[i][i] = 1; 43 | while(n){ 44 | if(n & 1) ans = mult(ans,v,mod); 45 | v = mult(v,v,mod); 46 | n = n >> 1; 47 | } 48 | return ans; 49 | } -------------------------------------------------------------------------------- /content/algorithms/mo-rollback.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Allow us to answer queries offline with sqrt decomposition 3 | *Status:* Tested 4 | */ 5 | struct query { 6 | ll l, r, i; 7 | }; 8 | 9 | template 10 | struct rollback_mo_algorithm { 11 | vector ans; 12 | template 13 | rollback_mo_algorithm(vector &v, vector &queries, Args... args) { 14 | ll block_sz = sqrtl(v.size()); 15 | ans.resize(queries.size()); 16 | T2 ds(args...); 17 | sort(queries.begin(), queries.end(), [&](auto &a, auto &b) { 18 | return a.l/block_sz != b.l/block_sz ? a.l/block_sz < b.l/block_sz : a.r < b.r; 19 | }); 20 | ll t = 0, last, border, last_block = -1, block; 21 | for(ll i = 0; i < queries.size(); i++) { 22 | block = queries[i].l / block_sz; 23 | if (block == queries[i].r/block_sz) { 24 | T2 tmp(args...); 25 | for (ll k = queries[i].l; k <= queries[i].r; k++) 26 | tmp.add(v[k]); 27 | ans[queries[i].i] = tmp.answer(queries[i]); 28 | continue; 29 | } 30 | if(last_block != block) { 31 | ds = T2(args...); 32 | border = block_sz * (block + 1); 33 | last = border; 34 | } 35 | last_block = block; 36 | for(ll k = last + 1; k <= queries[i].r; k++) ds.add(v[k]); 37 | t = ds.snapshot(); 38 | for(ll k = queries[i].l; k <= border; k++) ds.add(v[k]); 39 | ans[queries[i].i] = ds.answer(queries[i]); 40 | ds.rollback(t); 41 | last = queries[i].r; 42 | } 43 | } 44 | }; 45 | -------------------------------------------------------------------------------- /.github/workflows/release-new-version.yml: -------------------------------------------------------------------------------- 1 | name: release-new-version 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | 7 | jobs: 8 | compile_and_release: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v4 15 | 16 | - name: Install Typst 17 | run: | 18 | wget https://github.com/typst/typst/releases/latest/download/typst-x86_64-unknown-linux-musl.tar.xz 19 | tar -xf typst-x86_64-unknown-linux-musl.tar.xz 20 | sudo mv typst-x86_64-unknown-linux-musl/typst /usr/local/bin/ 21 | 22 | - name: Compile Document 23 | run: | 24 | typst compile main.typ 25 | ls -al # List files to check if main.pdf exists 26 | 27 | - name: Generate version tag 28 | id: version 29 | run: | 30 | echo "date=$(date +'%Y.%m.%d')" >> $GITHUB_OUTPUT 31 | echo "sha=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 32 | 33 | - name: Create Release 34 | id: create_release 35 | uses: softprops/action-gh-release@v2 36 | with: 37 | tag_name: ${{ steps.version.outputs.date }}-${{ steps.version.outputs.sha }} 38 | name: "Release ${{ steps.version.outputs.date }}-${{ steps.version.outputs.sha }}" 39 | generate_release_notes: true 40 | files: main.pdf 41 | env: 42 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 43 | 44 | - name: Upload compiled document as release asset 45 | if: steps.create_release.outputs.upload_url != '' 46 | run: echo "✅ main.pdf attached to release ${{ steps.create_release.outputs.upload_url }}" 47 | -------------------------------------------------------------------------------- /content/maths/ntt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Same utility as FFT but with some magic primes, runs in $O(n log n)$ with better constant 3 | Posible primes and their roots: 4 | - 998244353, 3 5 | - 9223372036737335297, 3 6 | *Status:* Tested only using 998244353 as mod 7 | */ 8 | template 9 | struct NTT { 10 | void ntt(int* x, int* temp, int* roots, int N, int skip) { 11 | if (N == 1) return; 12 | int n2 = N/2; 13 | ntt(x, temp, roots, n2, skip*2); 14 | ntt(x+skip, temp, roots, n2, skip*2); 15 | for (int i = 0; i < N; i++) temp[i] = x[i*skip]; 16 | for (int i = 0; i < n2; i++) { 17 | int s = temp[2*i], t = temp[2*i+1] * roots[skip*i]; 18 | x[skip*i] = (s + t) % mod; 19 | x[skip*(i+n2)] = (s - t) % mod; 20 | } 21 | } 22 | void ntt(vector& x, bool inv = false) { 23 | int e = binpow(root, (mod-1)/(x.size()), mod); 24 | if (inv) e = binpow(e, mod-2, mod); 25 | vector roots(x.size(), 1), temp = roots; 26 | for (int i = 1; i < x.size(); i++) roots[i] = roots[i-1] * e % mod; 27 | ntt(&x[0], &temp[0], &roots[0], x.size(), 1); 28 | } 29 | vector conv(vector a, vector b) { 30 | int s = a.size()+b.size()-1; 31 | if (s <= 0) return {}; 32 | int L = s > 1 ? 32 - __builtin_clz(s - 1) : 0, n = 1 << L; 33 | a.resize(n); ntt(a); 34 | b.resize(n); ntt(b); 35 | vector c(n); int d = binpow(n, mod-2, mod); 36 | for (int i = 0; i < n; i++) c[i] = a[i] * b[i] % mod * d % mod; 37 | ntt(c, true); c.resize(s); 38 | for (int i = 0; i < n; i++) if(c[i] < 0) c[i] += mod; 39 | return c; 40 | } 41 | }; -------------------------------------------------------------------------------- /content/data-structures/persistent-segment-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Segment tree but saves a new version of the tree for each update, build $O(n)$, query $O(log n)$, new nodes for each update $O(log n)$ 3 | *Status:* Tested on CSES 4 | */ 5 | template 6 | struct persistent_segment_tree { 7 | vector ST; 8 | vector L, R; 9 | int n, rt; 10 | persistent_segment_tree(int n): ST(1, T()), L(1, 0), R(1, 0), n(n), rt(0) {} 11 | int new_node(T v, int l = 0, int r = 0) { 12 | int ks = ST.size(); 13 | ST.push_back(v); L.push_back(l); R.push_back(r); 14 | return ks; 15 | } 16 | int update(int k, int l, int r, int p, T v) { 17 | int ks = new_node(ST[k], L[k], R[k]); 18 | if (l == r) { 19 | ST[ks] = v; return ks; 20 | } 21 | int m = (l + r) / 2, ps; 22 | if (p <= m) { 23 | ps = update(L[ks], l, m, p, v); 24 | L[ks] = ps; 25 | } else { 26 | ps = update(R[ks], m + 1, r, p, v); 27 | R[ks] = ps; 28 | } 29 | ST[ks] = _m(ST[L[ks]], ST[R[ks]]); 30 | return ks; 31 | } 32 | T query(int k, int l, int r, int a, int b) { 33 | if (l >= a and r <= b) 34 | return ST[k]; 35 | int m = (l + r) / 2; 36 | if (b <= m) 37 | return query(L[k], l, m, a, b); 38 | if (a > m) 39 | return query(R[k], m + 1, r, a, b); 40 | return _m(query(L[k], l, m, a, b), query(R[k], m + 1, r, a, b)); 41 | } 42 | int update(int k, int p, T v) { 43 | return rt = update(k, 0, n - 1, p, v); 44 | } 45 | int update(int p, T v) { 46 | return update(rt, p, v); 47 | } 48 | T query(int k, int a, int b) { 49 | return query(k, 0, n - 1, a, b); 50 | } 51 | }; -------------------------------------------------------------------------------- /content/strings/suffix-array.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Suffix array construction with LCP array using radix sort, $O(n log n)$ 3 | *Status:* Tested 4 | */ 5 | struct SA { 6 | int n; 7 | vector C, R, R_, sa, sa_, lcp; 8 | inline int gr(int i) { return i < n ? R[i] : 0; } 9 | void csort(int maxv, int k) { 10 | C.assign(maxv + 1, 0); 11 | for (int i = 0; i < n; i++) C[gr(i + k)]++; 12 | for (int i = 1; i < maxv + 1; i++) C[i] += C[i - 1]; 13 | for (int i = n - 1; i >= 0; i--) sa_[--C[gr(sa[i] + k)]] = sa[i]; 14 | sa.swap(sa_); 15 | } 16 | void getSA(vector& s) { 17 | R = R_ = sa = sa_ = vector(n); 18 | for (ll i = 0; i < n; i++) sa[i] = i; 19 | sort(sa.begin(), sa.end(), [&s](int i, int j) { return s[i] < s[j]; }); 20 | int r = R[sa[0]] = 1; 21 | for (ll i = 1; i < n; i++) R[sa[i]] = (s[sa[i]] != s[sa[i - 1]]) ? ++r : r; 22 | for (int h = 1; h < n && r < n; h <<= 1) { 23 | csort(r, h); 24 | csort(r, 0); 25 | r = R_[sa[0]] = 1; 26 | for (int i = 1; i < n; i++) { 27 | if (R[sa[i]] != R[sa[i - 1]] || gr(sa[i] + h) != gr(sa[i - 1] + h)) r++; 28 | R_[sa[i]] = r; 29 | } 30 | R.swap(R_); 31 | } 32 | } 33 | void getLCP(vector &s) { 34 | lcp.assign(n, 0); 35 | int k = 0; 36 | for (ll i = 0; i < n; i++) { 37 | int r = R[i] - 1; 38 | if (r == n - 1) { 39 | k = 0; 40 | continue; 41 | } 42 | int j = sa[r + 1]; 43 | while (i + k < n && j + k < n && s[i + k] == s[j + k]) k++; 44 | lcp[r] = k; 45 | if (k) k--; 46 | } 47 | } 48 | SA(vector &s) { 49 | n = s.size(); 50 | getSA(s); 51 | getLCP(s); 52 | } 53 | }; -------------------------------------------------------------------------------- /content/geometry/point-2d.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Just a 2D Point 3 | *Status:* Tested 4 | */ 5 | template struct Point2D { 6 | T x, y; 7 | Point2D(){}; 8 | Point2D(T x_, T y_) : x(x_), y(y_) {} 9 | Point2D &operator=(Point2D t) { 10 | x = t.x, y = t.y; 11 | return *this; 12 | } 13 | Point2D &operator+=(Point2D t) { 14 | x += t.x, y += t.y; 15 | return *this; 16 | } 17 | Point2D operator-(Point2D t) { return {x - t.x, y - t.y}; } 18 | Point2D operator+(Point2D t) { return {x + t.x, y + t.y}; } 19 | Point2D operator*(T t) { return {x * t, y * t}; } 20 | Point2D operator/(T t) { return {x / t, y / t}; } 21 | Point2D &operator-=(Point2D t) { 22 | x -= t.x, y -= t.y; 23 | return *this; 24 | } 25 | Point2D &operator*=(Point2D t) { 26 | x *= t.x, y *= t.y; 27 | return *this; 28 | } 29 | Point2D &operator/=(Point2D t) { 30 | x /= t.y, y /= t.y; 31 | return *this; 32 | } 33 | T operator|(Point2D b) { return x * b.x + y * b.y; } 34 | T operator^(Point2D b) { return x * b.y - y * b.x; } 35 | T cross(Point2D a, Point2D b) { return (a - *this) ^ (b - *this); } 36 | T norm() { return (*this) | (*this); } 37 | T sqdist(Point2D b) { return ((*this) - b).norm(); } 38 | double abs() { return sqrt(norm()); } 39 | double proj(Point2D b) { return (*this | b) / b.abs(); } 40 | double angle(Point2D b) { 41 | return acos(((*this) | b) / this->abs() / b.abs()); 42 | } 43 | Point2D rotate(T a) { 44 | return {cosl(a) * x - sinl(a) * y, sinl(a) * x + cosl(a) * y}; 45 | } 46 | }; 47 | template Point2D operator*(T a, Point2D b) { return b * a; } 48 | -------------------------------------------------------------------------------- /content/maths/simplex.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Optimizes linear function, based of linear restrictions, in $O(n^2)$ 3 | *Status:* Not tested 4 | */ 5 | template struct Simplex { 6 | T ans; 7 | vector> a; 8 | vector b,c,d; 9 | void pivot(int ii, int jj){ 10 | d[ii] = c[jj]; 11 | T s1 = a[ii][jj]; 12 | for (int i = 0; i < a[0].size(); i++) 13 | a[ii][i] /= s1; 14 | b[ii] /= s1; 15 | for (int i = 0; i < d.size(); i++){ 16 | if (i == ii || a[i][jj] == 0) continue; 17 | T s2 = a[i][jj]; 18 | for (int j = 0; j < a[0].size(); j++) 19 | a[i][j] -= s2*a[ii][j]; 20 | b[i] -= s2*b[ii]; 21 | } 22 | } 23 | bool next_point(){ 24 | int idx = -1; T mx; 25 | for (int i = 0; i < a[0].size(); i++){ 26 | T z = 0; 27 | for (int j = 0; j < d.size(); j++) 28 | z += a[j][i]*d[j]; 29 | if (idx == -1 || mx < c[i]-z) 30 | mx = c[i]-z, idx = i; 31 | } 32 | if (mx > 0){ 33 | int idx2 = -1; T mn; 34 | for (int i = 0; i < b.size(); i++){ 35 | if (a[i][idx] == 0 || b[i]/a[i][idx] <= 0) continue; 36 | if (idx2 == -1 || mn > b[i]/a[i][idx]) 37 | mn = b[i]/a[i][idx], idx2 = i; 38 | } 39 | pivot(idx2,idx); 40 | return 1; 41 | } 42 | return 0; 43 | } 44 | Simplex(vector> & _a, vector & _b, vector & _c) : a(_a),b(_b),c(_c){ 45 | d.resize(b.size(),0); 46 | while (next_point()); 47 | ans = 0; 48 | for (int i = 0; i < b.size(); i++) 49 | ans += b[i]*d[i]; 50 | } 51 | }; -------------------------------------------------------------------------------- /content/data-structures/range-query-constant.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Range queries, build $O(n)$, query $O(1)$, positions [0, n - 1], merge must be overlapping friendly, for example min,max,gcd and lcm 3 | *Status:* Tested on CSES 4 | */ 5 | template 6 | struct range_query { 7 | int n,sz,ld,bl; vector q; 8 | vector> st; vector arr; 9 | range_query(vector & a){ 10 | n = a.size(); sz = log2(n); 11 | bl = (n+sz-1)/sz; ld = log2(bl); arr = a; 12 | st.assign(bl,vector(ld+1)); q.resize(n); 13 | for (int i = 0; i < n; i++){ 14 | st[i/sz][0] = ((i%sz == 0)?a[i]:merge(st[i/sz][0],a[i])); 15 | int last = a[i]; q[i] = ((i > 0)?q[i-1]:0); 16 | while (q[i] != 0 && merge(a[i-1-__builtin_ctz(q[i])],last) == last) 17 | q[i] ^= (1<<__builtin_ctz(q[i])); 18 | q[i] = (q[i]<<1|1); q[i] &= (1< 7 | pair, Point2D> nearestPoints(vector> &P, int l, int r) { 8 | const T INF = 1e10; 9 | if (r-l == 1) return {P[l], P[r]}; 10 | if (l >= r) return {{INF, INF}, {-INF, -INF}}; 11 | 12 | int m = (l+r)/2; 13 | pair, Point2D> D1, D2, D; 14 | D1 = nearestPoints(P, l, m); 15 | D2 = nearestPoints(P, m+1, r); 16 | D = (D1.first.sqdist(D1.second) <= D2.first.sqdist(D2.second) ? D1 : D2); 17 | 18 | T d = D.first.sqdist(D.second), x_center = (P[m].x + P[m+1].x)/2; 19 | vector> Pk; 20 | for (int i = l; i <= r; i++) 21 | if (sq(P[i].x-x_center) <= d) 22 | Pk.push_back(P[i]); 23 | 24 | sort(Pk.begin(), Pk.end(), [](const Point2D p1, const Point2D p2) { 25 | return p1.y != p2.y ? p1.y < p2.y : p1.x < p2.x; 26 | }); 27 | 28 | for(int i = 0; i < Pk.size(); ++i) { 29 | for(int j = i-1; j >= 0; --j) { 30 | if(sq(Pk[i].y-Pk[j].y) > d) break; 31 | if(Pk[i].sqdist(Pk[j]) <= D.first.sqdist(D.second)) 32 | D = {Pk[i],Pk[j]}; 33 | } 34 | for(int j = i+1; j < Pk.size(); ++j) { 35 | if(sq(Pk[i].y-Pk[j].y) > d) break; 36 | if(Pk[i].sqdist(Pk[j]) <= D.first.sqdist(D.second)) 37 | D = {Pk[i],Pk[j]}; 38 | } 39 | } 40 | 41 | return D; 42 | } 43 | 44 | template 45 | pair, Point2D> nearestPoints(vector> &P) { 46 | sort(P.begin(), P.end(), [](const Point2D &p1, const Point2D &p2) { 47 | if (p1.x == p2.x) return p1.y < p2.y; 48 | return p1.x < p2.x; 49 | }); 50 | 51 | return nearestPoints(P, 0, P.size()-1); 52 | } -------------------------------------------------------------------------------- /scripts/check-tracker.py: -------------------------------------------------------------------------------- 1 | import yaml 2 | import sys 3 | import os 4 | 5 | # TODO: show files tracked but not existing 6 | # TODO: implement auto-fix option 7 | 8 | def dfs_files(base_directory): 9 | file_list = [] 10 | for root, dirs, files in os.walk(base_directory): 11 | for file in files: 12 | file_list.append(os.path.relpath(os.path.join(root, file), base_directory)) 13 | return file_list 14 | 15 | def files_tracked(tracker_dict): 16 | path = [] 17 | files = [] 18 | def dfs(current_dict): 19 | for element in current_dict: 20 | if isinstance(element, str): 21 | files.append(os.path.join(*path, element)) 22 | else: 23 | for key in element: 24 | path.append(key) 25 | dfs(element[key]) 26 | path.pop() 27 | dfs(tracker_dict["content"]) 28 | return files 29 | 30 | def main(tracker, content_directory): 31 | with open(tracker, 'r') as file: 32 | tracked_files = yaml.safe_load(file) 33 | 34 | existing_files = set(dfs_files(content_directory)) 35 | 36 | tracked_files = files_tracked(tracked_files) 37 | 38 | for file in tracked_files: 39 | existing_files.discard(file) 40 | 41 | if len(existing_files) == 0: 42 | print("All files are tracked.") 43 | else: 44 | print("Untracked files:") 45 | for file in existing_files: 46 | print(file) 47 | exit(1) 48 | 49 | if __name__ == "__main__": 50 | arguments = sys.argv 51 | 52 | if len(arguments) != 3: 53 | print("Usage: python check-tracker.py ") 54 | sys.exit(1) 55 | 56 | tracker_file = arguments[1] 57 | base_directory = arguments[2] 58 | main(tracker_file, base_directory) -------------------------------------------------------------------------------- /content/graphs/euler-directed-graph.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Find Eulerian path in directed graphs using Hierholzer's algorithm 3 | *Status:* Tested 4 | */ 5 | bool euler_directed_graph(vector> &adj, vector &path){ 6 | path.resize(0); 7 | int n = adj.size(); 8 | vector indeg(n), outdeg(n); 9 | int v1 = -1, v2 = -1; 10 | for (int i = 0; i < n; i ++){ 11 | outdeg[i] = adj[i].size(); 12 | for (int x : adj[i]) 13 | indeg[x] ++; 14 | } 15 | for (int i = 0; i < n; i ++){ 16 | int dif = outdeg[i] - indeg[i]; 17 | if (dif == 1){ 18 | if (v1 == -1) v1 = i; 19 | else return false; 20 | } 21 | else if (dif == -1){ 22 | if (v2 == -1) v2 = i; 23 | else return false; 24 | } 25 | else if (dif != 0) return false; 26 | } 27 | if (v1 != v2 and (v1 == -1 or v2 == -1)) return false; 28 | int first = v1; 29 | if (v1 != -1) adj[v2].push_back(v1); 30 | else 31 | for (int i = 0; i < n; i ++) 32 | if (outdeg[i] > 0) 33 | first = i; 34 | stack st; 35 | st.push(first); 36 | vector res; 37 | while(!st.empty()){ 38 | int v = st.top(); 39 | if (outdeg[v] == 0){ 40 | res.push_back(v); 41 | st.pop(); 42 | } 43 | else{ 44 | st.push(adj[v][0]); 45 | outdeg[v] --; 46 | swap(adj[v][0], adj[v][outdeg[v]]); 47 | } 48 | } 49 | for (int i = 0; i < n; i ++) 50 | if (outdeg[i] != 0) 51 | return false; 52 | reverse(res.begin(), res.end()); 53 | if (v1 != -1){ 54 | for (int i = 0; i + 1 < res.size(); i ++){ 55 | if (res[i] == v2 && res[i + 1] == v1){ 56 | vector res2(res.begin() + i + 1, res.end()); 57 | res2.insert(res2.end(), res.begin(), res.begin() + i + 1); 58 | res = res2; 59 | break; 60 | } 61 | } 62 | } 63 | path = res; 64 | return true; 65 | } 66 | -------------------------------------------------------------------------------- /content/graphs/centroid-decomposition.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* centroid decomposition algorithm 3 | *Status:* Partially tested 4 | */ 5 | struct centroid_decomp { 6 | int n; 7 | vector vis; 8 | vector subtr, parent; 9 | vector> adj; 10 | // Optional 11 | // Here you can insert the functions for traversing the partition 12 | // ---------- 13 | void dfs(int v,int p = -1){ 14 | for(int u: adj[v]){ 15 | if(u != p && !vis[u]) dfs(u,v); 16 | } 17 | } 18 | // ---------- 19 | 20 | int calculate_subtree(int v, int p){ 21 | subtr[v] = 1; 22 | for (int to : adj[v]){ 23 | if (to == p || vis[to]) continue; 24 | subtr[v] += calculate_subtree(to,v); 25 | } 26 | return subtr[v]; 27 | } 28 | int get_centroid(int v, int p, int sz){ 29 | for (int to : adj[v]){ 30 | if (to == p || vis[to]) continue; 31 | if (subtr[to]*2> sz) return get_centroid(to,v,sz); 32 | } 33 | return v; 34 | } 35 | int build(int v = 0){ 36 | int centroid = get_centroid(v,v,calculate_subtree(v,v)); 37 | // Optional 38 | // Here you can call functions for traversing the partition 39 | // ---------- 40 | dfs(centroid); 41 | // ---------- 42 | vis[centroid] = 1; 43 | for (int to : adj[centroid]){ 44 | if (vis[to]) continue; 45 | build(to); 46 | // Optional 47 | // ---------- 48 | // Save parent centroid (Optional) 49 | parent[build(to)] = centroid; 50 | // ---------- 51 | } 52 | return centroid; 53 | } 54 | centroid_decomp(vector> &_adj){ 55 | adj = _adj; 56 | n = adj.size(); 57 | subtr.resize(n,0); 58 | parent.resize(n,-1); 59 | vis.resize(n,0); 60 | build(); 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /content/graphs/min-cost-flow.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Abner Vidal 3 | *Description:* Minimun cost flow with complexity $O (F(|E||V|log(|E|)))$ 4 | *Status:* Tested on CSES 5 | */ 6 | template 7 | struct min_cost_flow { 8 | struct edge {int v; T1 c,f; T2 w; }; 9 | vvi g; vector dist,pot; vector fl; 10 | vector vis; vector par; vector e; 11 | min_cost_flow(int n):g(n),dist(n),pot(n),fl(n),vis(n),par(n){} 12 | void add_edge(int u, int v, T1 c, T2 w){ 13 | int k = e.size(); 14 | e.push_back({v,c,0,w}); e.push_back({u,c,c,-w}); 15 | g[u].push_back(k); g[v].push_back(k^1); 16 | } 17 | using pli = pair; 18 | void dijk(int s){ 19 | fill(dist.begin(),dist.end(),numeric_limits::max()); 20 | fill(vis.begin(),vis.end(),0); fl[s] = numeric_limits::max(); 21 | priority_queue,greater> q; 22 | q.push({0,s}); dist[s] = 0; 23 | while (!q.empty()){ 24 | pli p = q.top(); q.pop(); int x = p.second; 25 | if (vis[x]) continue; vis[x] = 1; 26 | for (int to : g[x]){ 27 | T2 d2 = p.first+e[to].w+pot[x]-pot[e[to].v]; 28 | if (!vis[e[to].v] && e[to].f < e[to].c && d2 < dist[e[to].v]){ 29 | dist[e[to].v] = d2; fl[e[to].v] = min(fl[x],e[to].c-e[to].f); 30 | par[e[to].v] = to; q.push({d2,e[to].v}); 31 | } 32 | } 33 | } 34 | } 35 | T2 calc_flow(int s, int t, T1 _f){ 36 | T2 cost = 0; 37 | while (1){ 38 | dijk(s); 39 | if (!vis[t]) return -1; 40 | for (int i = 0; i < g.size(); i++) 41 | dist[i] += pot[i]-pot[s]; 42 | T1 mnf = min(_f,fl[t]); 43 | cost += dist[t]*mnf; 44 | int cur = t; 45 | while (cur != s){ 46 | e[par[cur]].f += mnf; 47 | e[par[cur]^1].f -= mnf; 48 | cur = e[par[cur]^1].v; 49 | } 50 | dist.swap(pot); 51 | _f -= mnf; 52 | if (!_f) break; 53 | } 54 | return cost; 55 | } 56 | }; -------------------------------------------------------------------------------- /content/combinatorial/simulated-annealing.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Optimizes the function `eval` by exploring the neighbor solutions using simulated annealing. 3 | - `time_limit`: The maximum time to run the algorithm. 4 | - `t_i`: Initial temperature. 5 | - `t_f`: Final temperature. 6 | The algorithm works for both minimization, to maximize you should change `(old_val - new_val)` to `(new_val - old_val)` and (eval_nxt < best) to (eval_nxt > best) 7 | `P(old_val, new_val, temp)` computes the probability of accepting a worse solution based on the current temperature. 8 | Usage: 9 | - `T` is the data type of the answer. 10 | - `repr` is the data structure of the representation of the solution, it should contain the functions: init,eval,get_neighbor and rollback. 11 | Tips: 12 | - Always write your intermediate solution to a file periodically (e.g., every ~1 million iterations) to ensure partial scores if the process is interrupted. 13 | - To choose a good $t_i$ and $alpha$, start with a high $t_0$ and a low $alpha$, then adjust based on how the temperature and energy function behave. 14 | *Status:* Tested with sudoku. 15 | */ 16 | template 17 | struct simulated_annealing { 18 | T val; 19 | double get_time(){ return chrono::duration(chrono::high_resolution_clock::now().time_since_epoch()).count(); } 20 | double P(double old_val, double new_val, double temp) { return exp(((old_val-new_val))/temp); } 21 | simulated_annealing(double time_limit, double t_i, double t_f, repr & q){ 22 | q.init(); 23 | double st = get_time(); val = q.eval(); 24 | while (1){ 25 | double elapsed = get_time()-st; 26 | if (elapsed > time_limit) break; 27 | double ela_frac = elapsed/time_limit; 28 | double temp = t_i*pow(t_f/t_i,ela_frac); 29 | q.get_neighbor(); 30 | T new_val = q.eval(); 31 | if (new_val < val || ((double)rand())/RAND_MAX < P(val,new_val,temp)){ 32 | val = new_val; 33 | } else { 34 | q.rollback(); 35 | } 36 | } 37 | } 38 | }; -------------------------------------------------------------------------------- /content/data-structures/dynamic-segment-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* The nodes are created when the some value is updated, enabling queries in intervals like $[0, 10^12]$. Overall complexity is $O(Q log N)$ 3 | *Status:* Not tested 4 | */ 5 | template < 6 | class T, // Data type of the nodes 7 | class MAXi, // Data type of the ranges (ll or i128) 8 | T merge(T, T), // Merge 9 | T init(MAXi, MAXi) // Default value for [a, b] 10 | > 11 | struct dynamic_segment_tree { 12 | vector ST; vectorL, R; 13 | MAXi n; int n_count; 14 | dynamic_segment_tree (MAXi n, int r) : 15 | n(n),n_count(1),L(1),R(1),ST(1){ 16 | ST.reserve(r); 17 | L.reserve(r); 18 | R.reserve(r); 19 | ST[0] = init(0, n - 1); 20 | } 21 | int addNode(MAXi l, MAXi r){ 22 | L.push_back(0); 23 | R.push_back(0); 24 | ST.push_back(init(l, r)); 25 | return n_count ++; 26 | } 27 | T query(int i, MAXi l, MAXi r, MAXi a, MAXi b) { 28 | if (a <= l and r <= b) 29 | return ST[i]; 30 | MAXi mid = ((l + r) >> 1LL); 31 | if (b <= mid) 32 | return (L[i] != 0 ? query(L[i], l, mid, a, b) : init(l, mid)); 33 | else if (a > mid) 34 | return (R[i] != 0 ? query(R[i], mid + 1, r, a, b) : init(mid + 1, r)); 35 | if (L[i] == 0) L[i] = addNode(l, mid); 36 | if (R[i] == 0) R[i] = addNode(mid + 1, r); 37 | return merge(query(L[i], l, mid, a, b), query(R[i], mid + 1, r, a, b)); 38 | } 39 | T query(MAXi a, MAXi b) { 40 | return query(0, 0, n - 1, a, b); 41 | } 42 | void update(int i, MAXi l, MAXi r, MAXi p, T v) { 43 | if (l == r){ 44 | ST[i] = v; return; 45 | } 46 | MAXi mid = (l + r) / 2LL; 47 | if (p <= mid) 48 | update(L[i] != 0 ? L[i] : L[i] = addNode(l, mid), l, mid, p, v); 49 | else 50 | update(R[i] != 0 ? R[i] : R[i] = addNode(mid + 1, r), mid + 1, r, p, v); 51 | ST[i] = merge( 52 | L[i] != 0 ? ST[L[i]] : init(l, mid), 53 | R[i] != 0 ? ST[R[i]] : init(mid + 1, r) 54 | ); 55 | } 56 | void update(MAXi pos, T v) { 57 | update(0, 0, n - 1, pos, v); 58 | } 59 | }; -------------------------------------------------------------------------------- /content/strings/aho-corasick.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Aho-Corasick algorithm for multiple pattern matching in text 3 | *Status:* Tested 4 | */ 5 | struct AhoCorasick { 6 | enum { 7 | alpha = 26, first = 'a' 8 | }; // change this! 9 | struct Node { 10 | // (nmatches is optional) 11 | int back, next[alpha], start = -1, end = -1, nmatches = 0; 12 | Node(int v) { 13 | memset(next, v, sizeof(next)); 14 | } 15 | }; 16 | vector < Node > N; 17 | vi backp; 18 | void insert(string & s, int j) { 19 | assert(!s.empty()); 20 | int n = 0; 21 | for (char c: s) { 22 | int & m = N[n].next[c - first]; 23 | if (m == -1) { 24 | n = m = sz(N); 25 | N.emplace_back(-1); 26 | } else n = m; 27 | } 28 | if (N[n].end == -1) N[n].start = j; 29 | backp.push_back(N[n].end); 30 | N[n].end = j; 31 | N[n].nmatches++; 32 | } 33 | AhoCorasick(vector < string > & pat): N(1, -1) { 34 | rep(i, 0, sz(pat)) insert(pat[i], i); 35 | N[0].back = sz(N); 36 | N.emplace_back(0); 37 | 38 | queue < int > q; 39 | for (q.push(0); !q.empty(); q.pop()) { 40 | int n = q.front(), prev = N[n].back; 41 | rep(i, 0, alpha) { 42 | int & ed = N[n].next[i], y = N[prev].next[i]; 43 | if (ed == -1) ed = y; 44 | else { 45 | N[ed].back = y; 46 | (N[ed].end == -1 ? N[ed].end : backp[N[ed].start]) = N[y].end; 47 | N[ed].nmatches += N[y].nmatches; 48 | q.push(ed); 49 | } 50 | } 51 | } 52 | } 53 | vi find(string word) { 54 | int n = 0; 55 | vi res; // ll count = 0; 56 | for (char c: word) { 57 | n = N[n].next[c - first]; 58 | res.push_back(N[n].end); 59 | // count += N[n].nmatches; 60 | } 61 | return res; 62 | } 63 | vector < vi > findAll(vector < string > & pat, string word) { 64 | vi r = find(word); 65 | vector < vi > res(sz(word)); 66 | rep(i, 0, sz(word)) { 67 | int ind = r[i]; 68 | while (ind != -1) { 69 | res[i - sz(pat[ind]) + 1].push_back(ind); 70 | ind = backp[ind]; 71 | } 72 | } 73 | return res; 74 | } 75 | }; -------------------------------------------------------------------------------- /content/graphs/eppstein.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Solve k-shortest path problem 3 | *Status:* Tested on josupo.jp and CSES 4 | */ 5 | struct Eppstein { 6 | #define x first 7 | #define y second 8 | using T = int; const T INF = 1e18; 9 | using Edge = pair; 10 | struct Node { int E[2] = {}, s{0}; Edge x; }; 11 | T shortest; 12 | priority_queue> Q; 13 | vector P{1}; vector h; 14 | Eppstein(vector>& G, int s, int t) { 15 | int n = G.size(); 16 | vector> H(n); 17 | for(int i = 0; i < n; i++) 18 | for (Edge &e : G[i]) 19 | H[e.x].push_back({i, e.y}); 20 | vector ord, par(n, -1); 21 | vector d(n, -INF); 22 | Q.push({d[t] = 0, t}); 23 | while (!Q.empty()) { 24 | auto v = Q.top(); Q.pop(); 25 | if (d[v.y] == v.x) { 26 | ord.push_back(v.y); 27 | for (Edge &e : H[v.y]) 28 | if (v.x-e.y > d[e.x]) { 29 | Q.push({d[e.x] = v.x-e.y, e.x}); 30 | par[e.x] = v.y; 31 | } 32 | } 33 | } 34 | if ((shortest = -d[s]) >= INF) return; 35 | h.resize(n); 36 | for (int v : ord) { 37 | int p = par[v]; 38 | if (p+1) h[v] = h[p]; 39 | for (Edge &e : G[v]) 40 | if (d[e.x] > -INF) { 41 | T k = e.y - d[e.x] + d[v]; 42 | if (k or e.x != p) h[v] = push(h[v], {e.x, k}); 43 | else p = -1; 44 | } 45 | } 46 | P[0].x.x = s; 47 | Q.push({0, 0}); 48 | } 49 | int push(int t, Edge x) { 50 | P.push_back(P[t]); 51 | if (!P[t = int(P.size())-1].s or P[t].x.y >= x.y) 52 | swap(x, P[t].x); 53 | if (P[t].s) { 54 | int i = P[t].E[0], j = P[t].E[1]; 55 | int d = P[i].s > P[j].s; 56 | int k = push(d ? j : i, x); 57 | P[t].E[d] = k; 58 | } 59 | P[t].s++; 60 | return t; 61 | } 62 | int nextPath() { 63 | if (Q.empty()) return -1; 64 | auto v = Q.top(); Q.pop(); 65 | for (int i : P[v.y].E) if (i) 66 | Q.push({ v.x-P[i].x.y+P[v.y].x.y, i }); 67 | int t = h[P[v.y].x.x]; 68 | if (t) Q.push({ v.x - P[t].x.y, t }); 69 | return shortest - v.x; 70 | } 71 | }; -------------------------------------------------------------------------------- /content/general/troubleshoot.typ: -------------------------------------------------------------------------------- 1 | *Pre-submit:* 2 | - Write a few simple test cases if sample is not enough. 3 | - Are time limits close? If so, generate max cases. 4 | - Is the memory usage fine? 5 | - Could anything overflow? 6 | - Make sure to submit the right file. 7 | 8 | *Wrong answer:* 9 | - Print your solution! Print debug output, as well. 10 | - Are you clearing all data structures between test cases? 11 | - Can your algorithm handle the whole range of input? 12 | - Read the full problem statement again. 13 | - Do you handle all corner cases correctly? 14 | - Have you understood the problem correctly? 15 | - Any uninitialized variables? 16 | - Any overflows? 17 | - Confusing N and M, i and j, etc.? 18 | - Are you sure your algorithm works? 19 | - What special cases have you not thought of? 20 | - Are you sure the STL functions you use work as you think? 21 | - Add some assertions, maybe resubmit. 22 | - Create some testcases to run your algorithm on. 23 | - Go through the algorithm for a simple case. 24 | - Go through this list again. 25 | - Explain your algorithm to a teammate. 26 | - Ask the teammate to look at your code. 27 | - Go for a small walk, e.g. to the toilet. 28 | - Is your output format correct? (including whitespace) 29 | - Are you using modular inverse? 30 | - Rewrite your solution from the start or let a teammate do it. 31 | 32 | *Runtime error:* 33 | - Have you tested all corner cases locally? 34 | - Any uninitialized variables? 35 | - Are you reading or writing outside the range of any vector? 36 | - Any assertions that might fail? 37 | - Any possible division by 0? (mod 0 for example) 38 | - Any possible infinite recursion? 39 | - Invalidated pointers or iterators? 40 | - Are you using too much memory? 41 | - Debug with resubmits (e.g. remapped signals, see Various). 42 | 43 | *Time limit exceeded:* 44 | - Do you have any possible infinite loops? 45 | - What is the complexity of your algorithm? 46 | - Are you copying a lot of unnecessary data? (References) 47 | - How big is the input and output? (consider scanf) 48 | - Avoid vector, map. (use arrays/unordered_map) 49 | - What do your teammates think about your algorithm? 50 | 51 | *Memory limit exceeded:* 52 | - What is the max amount of memory your algorithm should need? 53 | - Are you clearing all data structures between test cases? -------------------------------------------------------------------------------- /content/graphs/kosaraju.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* SCC in $O(V + E)$ 3 | *Status:* Tested, but needs to be re-written, is too large 4 | */ 5 | template 6 | struct SCC { 7 | vector> GT, G, SCC_G, SCC_GT, comp_nodes; 8 | vector data, cdata; 9 | stack order; 10 | vector comp, dp; 11 | vector visited; 12 | T (*cfunc)(T, T); 13 | int comp_count = 0; 14 | void topsort(int u) { 15 | visited[u] = true; 16 | for (int v : G[u]) 17 | if (!visited[v]) 18 | topsort(v); 19 | order.push(u); 20 | } 21 | void build_component(int u) { 22 | visited[u] = true; 23 | for (int v : GT[u]) 24 | if (!visited[v]) 25 | build_component(v); 26 | comp[u] = comp_count; 27 | comp_nodes[comp_count].push_back(u); 28 | } 29 | void compress_graph() { 30 | for (int u = 0; u < G.size(); u++) 31 | cdata[comp[u]] = cfunc(cdata[comp[u]], data[u]); 32 | for (int u = 0; u < G.size(); u++) 33 | for (int v : G[u]) 34 | if (comp[u] != comp[v]) { 35 | SCC_G[comp[u]].push_back(comp[v]); 36 | SCC_GT[comp[v]].push_back(comp[u]); 37 | } 38 | } 39 | T process(int cmp, T (*func)(T a, T b), T (*merge)(T a, T b)) { 40 | if (dp[cmp]) return dp[cmp]; 41 | dp[cmp] = cdata[cmp]; 42 | for (int u : SCC_G[cmp]) 43 | dp[cmp] = merge(dp[cmp], func(process(u, func, merge), cdata[cmp])); 44 | return dp[cmp]; 45 | } 46 | SCC(vector> &G, vector &data, T (*cfunc)(T a, T b), T comp_identity, T dp_identity): cfunc(cfunc), G(G), data(data) { 47 | GT.resize(G.size()); comp_nodes.resize(G.size()); 48 | visited.assign(G.size(), 0); 49 | cdata.assign(G.size(), comp_identity); 50 | comp.assign(G.size(), 0); 51 | SCC_G.resize(G.size()); SCC_GT.resize(G.size()); 52 | dp.assign(G.size(), dp_identity); 53 | for (int u = 0; u < G.size(); u++) 54 | for (int v : G[u]) 55 | GT[v].push_back(u); 56 | for (int u = 0; u < G.size(); u++) 57 | if (!visited[u]) 58 | topsort(u); 59 | visited.assign(G.size(), 0); 60 | while (!order.empty()) { 61 | int u = order.top(); 62 | order.pop(); 63 | if (visited[u]) continue; 64 | build_component(u); 65 | comp_count++; 66 | } 67 | compress_graph(); 68 | } 69 | }; -------------------------------------------------------------------------------- /content/data-structures/bit-vector.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* A more flexible dynamic bit_vector, with operations `access`, `set`, `not` and `push_back` 3 | *Status:* Partially tested 4 | */ 5 | struct bit_vector { 6 | uint64_t size; 7 | vector< uint64_t > bv; 8 | bit_vector() : size(0) {} 9 | uint64_t get(uint64_t i) const { 10 | uint64_t b = i / 64; 11 | uint64_t ib = i % 64; 12 | return (bv[b] & (1ULL << ib)) >> ib; 13 | } 14 | void set(uint64_t i) { 15 | uint64_t b = i / 64; 16 | uint64_t ib = i % 64; 17 | bv[b] |= (1ULL << ib); 18 | } 19 | void push_back(uint64_t bit) { 20 | if(size % 64 == 0) bv.push_back(0); 21 | uint64_t b = size / 64; 22 | uint64_t ib = size++ % 64; 23 | bv[b] |= (bit << ib); 24 | } 25 | bit_vector operator~() { 26 | bit_vector bv = *this; 27 | for(uint64_t i = 0; i < bv.bv.size(); i++) 28 | bv.bv[i] = ~bv.bv[i]; 29 | if(size % 64) 30 | for(uint64_t i = size % 64; i < 64; i++) 31 | bv.bv[bv.bv.size() - 1] &= (~(1ULL << i)); 32 | return bv; 33 | } 34 | friend std::ostream& operator<<(std::ostream& os, const bit_vector& bv) { 35 | for(uint64_t i = 0; i < bv.size; i++) { 36 | if(bv.bv[i / 64] < (1ULL << 32) && (i % 64) >= 32) cout << 0; 37 | else cout << ((bv.bv[i / 64] & (1ULL << (i % 64))) ? 1 : 0); 38 | } 39 | return os; 40 | } 41 | bit_vector& operator=(const bit_vector& o) { 42 | if (this != &o) 43 | size = o.size, bv = o.bv; 44 | return *this; 45 | } 46 | bool operator==(const bit_vector& o) const { 47 | if(size != o.size) return false; 48 | for(uint64_t i = 0; i < size; i++) 49 | if(get(i) != o.get(i)) return false; 50 | return true; 51 | } 52 | bool operator<(const bit_vector& o) const { 53 | for(uint64_t i = 0; i < size && i < o.size; i++) 54 | if(get(i) != o.get(i)) return get(i) < o.get(i); 55 | return size < o.size; 56 | } 57 | bool operator>(const bit_vector& o) const { 58 | for(uint64_t i = 0; i < size && i < o.size; i++) 59 | if(get(i) != o.get(i)) return get(i) > o.get(i); 60 | return size > o.size; 61 | } 62 | bool operator<=(const bit_vector& o) const { 63 | for(uint64_t i = 0; i < size && i < o.size; i++) 64 | if(get(i) != o.get(i)) return get(i) <= o.get(i); 65 | return size <= o.size; 66 | } 67 | bool operator>=(const bit_vector& o) const { 68 | for(uint64_t i = 0; i < size && i < o.size; i++) 69 | if(get(i) != o.get(i)) return get(i) >= o.get(i); 70 | return size >= o.size; 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /content/data-structures/iterative-segment-tree-lazy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Segment tree with lazy propagation, but now iterative. Build is $O(n)$, querys and updates are $O(log n)$ 3 | *Status:* Tested 4 | */ 5 | template 6 | struct segment_tree_lazy { 7 | int n,h; vector st; vector lazy; 8 | segment_tree_lazy(vector & a){ 9 | n = a.size(); h = sizeof(int)*8-__builtin_clz(n); 10 | st.resize(n<<1); lazy.resize(n); 11 | for (int i = 0; i < n; i++) st[n+i] = a[i]; 12 | for (int i = n-1; i > 0; i--) st[i] = merge(st[i<<1],st[i<<1|1]); 13 | } 14 | void calc(int pos, int sz){ 15 | st[pos] = merge(st[pos<<1],st[pos<<1|1]); 16 | if (lazy[pos].upd()) applyUpd(st[pos],lazy[pos],sz); 17 | } 18 | void apply(int pos, T2 val, int sz){ 19 | applyUpd(st[pos],val,sz); 20 | if (pos < n) pushUpd(val,lazy[pos],sz); 21 | } 22 | void push(int l, int r){ 23 | int s = h, sz = 1<<(h-1); 24 | for (l += n, r += n-1; s > 0; s--, sz >>= 1) 25 | for (int i = l>>s; i <= r>>s; i++) if (lazy[i].upd()){ 26 | apply(i<<1,lazy[i],sz); 27 | apply(i<<1|1,lazy[i],sz); 28 | lazy[i] = T2(); 29 | } 30 | } 31 | void update(int l, int r, T2 val){ 32 | push(l,l+1); push(r,r+1); 33 | bool cl = 0, cr = 0; int sz = 1; 34 | for (l += n, r += n+1; l < r; l >>= 1, r >>= 1, sz <<= 1){ 35 | if (cl) calc(l-1,sz); 36 | if (cr) calc(r,sz); 37 | if (l&1) apply(l++,val,sz), cl = 1; 38 | if (r&1) apply(--r,val,sz), cr = 1; 39 | } 40 | for (--l; r > 0; l >>= 1, r >>= 1, sz <<= 1){ 41 | if (cl) calc(l,sz); 42 | if (cr && (!cl || l != r)) calc(r,sz); 43 | } 44 | } 45 | T1 query(int l, int r){ 46 | push(l,l+1); push(r,r+1); 47 | T1 ansL, ansR; bool hasL = 0,hasR = 0; 48 | for (l += n, r += n+1; l < r; l >>= 1, r >>= 1){ 49 | if (l&1) ansL = (hasL?merge(ansL,st[l++]):st[l++]), hasL = 1; 50 | if (r&1) ansR = (hasR?merge(st[--r],ansR):st[--r]), hasR = 1; 51 | } 52 | if (!hasL) return ansR; if (!hasR) return ansL; 53 | return merge(ansL,ansR); 54 | } 55 | }; 56 | /* example of use */ 57 | struct lz { 58 | ll val; 59 | lz(){ val = 0; } 60 | bool upd(){ return (val != 0); } 61 | }; 62 | ll merge(ll & a, ll & b){ 63 | return a+b; 64 | } 65 | void applyUpd(ll & v, lz & u, int sz){ 66 | v += u.val*((ll)sz); 67 | } 68 | void pushUpd(lz & u1, lz & u2, int sz){ 69 | u2.val += u1.val; 70 | } -------------------------------------------------------------------------------- /content/data-structures/extended-segment-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* More flexible version of normal segment tree, same time complexities 3 | *Status:* Tested 4 | */ 5 | template 6 | struct extended_segment_tree{ 7 | vector ST; 8 | int n; 9 | void build(int i, int l, int r, vector &a){ 10 | if (l == r) { ST[i] = a[l]; return; } 11 | int mid = (l + r) / 2; 12 | build(i << 1, l, mid, a); 13 | build(i << 1 | 1, mid + 1, r, a); 14 | ST[i].build(&ST[i << 1], &ST[i << 1 | 1]); 15 | } 16 | extended_segment_tree(vector &a){ 17 | n = a.size(); ST.resize(n << 2 | 3); 18 | build(1, 0, n - 1, a); 19 | } 20 | query_output query(int i, int l, int r, int a, int b, query_input &q){ 21 | if (l >= a and r <= b) { return ST[i].query(q); } 22 | int mid = (l + r) / 2; 23 | if (b <= mid) return query(i << 1, l, mid, a, b, q); 24 | else if (a > mid) return query(i << 1 | 1, mid + 1, r, a, b, q); 25 | query_output R = query(i << 1 | 1, mid + 1, r, a, b, q); 26 | query_output L = query(i << 1, l, mid, a, b, q); 27 | return L.merge(&R); 28 | } 29 | query_output query(int l, int r, query_input &q){ 30 | return query(1, 0, n - 1, l, r, q); 31 | } 32 | void update(int i, int l, int r, int pos, tree_node &x){ 33 | if (l == r){ ST[i] = x; return; } 34 | int mid = (l + r) / 2; 35 | if (l <= mid) update(i << 1, l, mid, pos, x); 36 | if (r > mid) update(i << 1 | 1, mid + 1, r, pos, x); 37 | ST[i].update(pos - l, x); 38 | } 39 | void update(int pos, tree_node &x){ 40 | update(1, 0, n - 1, pos, x); 41 | } 42 | }; 43 | 44 | // Example 45 | struct query_output{ 46 | int v; 47 | query_output(int v) : v(v){} 48 | query_output merge(query_output *r){ 49 | return query_output(v + r->v); 50 | } 51 | }; 52 | typedef int query_input; 53 | struct tree_node{ 54 | int n; 55 | vector a; 56 | tree_node(){} 57 | tree_node(int x){ 58 | a.resize(1, x); 59 | n = 1; 60 | } 61 | void update(int pos, tree_node &x) { 62 | return; 63 | } 64 | query_output query(int v){ 65 | int left = 0, right = n - 1; 66 | while(left < right){ 67 | int mid = (left + right + 1) / 2; 68 | if (a[mid] <= v) left = mid; 69 | else right = mid - 1; 70 | } 71 | if (a[left] > v) left--; 72 | return query_output(n - 1 - left); 73 | } 74 | void build(tree_node *l, tree_node *r){ 75 | int nl = l->a.size(), nr = r->a.size(); 76 | int pl = 0, pr = 0; 77 | a.reserve(nl + nr); 78 | while(pl < nl || pr < nr){ 79 | if (pl == nl || (pr < nr and l->a[pl] >= r->a[pr])){ 80 | a.push_back(r->a[pr ++]); 81 | } 82 | else{ 83 | a.push_back(l->a[pl ++]); 84 | } 85 | } 86 | n = a.size(); 87 | } 88 | }; 89 | extended_segment_tree EST(a); -------------------------------------------------------------------------------- /content/data-structures/segment-tree-lazy.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Segment tree but with range updates, build $O(n)$, query and update $O(log n)$ 3 | *Status:* Highly tested 4 | */ 5 | template< 6 | class T1, // answer value stored on nodes 7 | class T2, // lazy update value stored on nodes 8 | T1 merge(T1, T1), 9 | void pushUpd(T2& /*parent*/, T2& /*child*/, int, int, int, int), // push update value from a node to another. parent -> child 10 | void applyUpd(T2&, T1&, int, int) // apply the update value of a node to its answer value. upd -> ans 11 | > 12 | struct segment_tree_lazy{ 13 | vector ST; vector lazy; vector upd; 14 | int n; 15 | void build(int i, int l, int r, vector&values){ 16 | if (l == r){ 17 | ST[i] = values[l]; 18 | return; 19 | } 20 | build(i << 1, l, (l + r) >> 1, values); 21 | build(i << 1 | 1, (l + r) / 2 + 1, r, values); 22 | ST[i] = merge(ST[i << 1], ST[i << 1 | 1]); 23 | } 24 | segment_tree_lazy() {} 25 | segment_tree_lazy(vector&values){ 26 | n = values.size(); ST.resize(n << 2 | 3); 27 | lazy.resize(n << 2 | 3); upd.resize(n << 2 | 3, false); 28 | build(1, 0, n - 1, values); 29 | } 30 | void push(int i, int l, int r){ 31 | if (upd[i]){ 32 | applyUpd(lazy[i], ST[i], l, r); 33 | if (l != r){ 34 | pushUpd(lazy[i], lazy[i << 1], l, r, l, (l + r) / 2); 35 | pushUpd(lazy[i], lazy[i << 1 | 1], l, r, (l + r) / 2 + 1, r); 36 | upd[i << 1] = 1; 37 | upd[i << 1 | 1] = 1; 38 | } 39 | upd[i] = false; 40 | lazy[i] = T2(); 41 | } 42 | } 43 | void update(int i, int l, int r, int a, int b, T2 &u){ 44 | if (l >= a and r <= b){ 45 | pushUpd(u, lazy[i], a, b, l, r); 46 | upd[i] = true; 47 | } 48 | push(i, l, r); 49 | if (l > b or r < a) return; 50 | if (l >= a and r <= b) return; 51 | update(i << 1, l, (l + r) >> 1, a, b, u); 52 | update(i << 1 | 1, (l + r) / 2 + 1, r, a, b, u); 53 | ST[i] = merge(ST[i << 1], ST[i << 1 | 1]); 54 | } 55 | void update(int a, int b, T2 u){ 56 | if (a > b){ 57 | update(0, b, u); 58 | update(a, n - 1, u); 59 | return ; 60 | } 61 | update(1, 0, n - 1, a, b, u); 62 | } 63 | T1 query(int i, int l, int r, int a, int b){ 64 | push(i, l, r); 65 | if (a <= l and r <= b) 66 | return ST[i]; 67 | int mid = (l + r) >> 1; 68 | if (mid < a) 69 | return query(i << 1 | 1, mid + 1, r, a, b); 70 | if (mid >= b) 71 | return query(i << 1, l, mid, a, b); 72 | return merge(query(i << 1, l, mid, a, b), query(i << 1 | 1, mid + 1, r, a, b)); 73 | } 74 | T1 query(int a, int b){ 75 | if (a > b) return merge(query(a, n - 1), query(0, b)); 76 | return query(1, 0, n - 1, a, b); 77 | } 78 | }; -------------------------------------------------------------------------------- /content/graphs/hld.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Javier Oliva 3 | *Description:* Answer queries in $O( log(V) dot A dot B )$, where $A$ is the complexity of merging two chains and $B$ is the complexity of the data structure query. 4 | *Status:* Partially tested 5 | */ 6 | template 7 | struct heavy_light { 8 | vector parent, depth, heavy, head, pos_down; 9 | int n, cur_pos_down; DS ds_down; 10 | int dfs(int v, vector < vector < int >> 11 | const & adj) { 12 | int size = 1; 13 | int max_c_size = 0; 14 | for (int c: adj[v]) 15 | if (c != parent[v]) { 16 | parent[c] = v, depth[c] = depth[v] + 1; 17 | int c_size = dfs(c, adj); 18 | size += c_size; 19 | if (c_size > max_c_size) 20 | max_c_size = c_size, heavy[v] = c; 21 | } 22 | return size; 23 | } 24 | void decompose(int v, int h, vector> 25 | const & adj, vector & a_down, vector & values) { 26 | head[v] = h, pos_down[v] = cur_pos_down++; 27 | a_down[pos_down[v]] = values[v]; 28 | if (heavy[v] != -1) 29 | decompose(heavy[v], h, adj, a_down, values); 30 | for (int c: adj[v]) { 31 | if (c != parent[v] && c != heavy[v]) 32 | decompose(c, c, adj, a_down, values); 33 | } 34 | } 35 | heavy_light(vector > &adj, vector & values) { 36 | n = adj.size(); 37 | parent.resize(n); 38 | depth.resize(n); 39 | heavy.resize(n, -1); 40 | head.resize(n); 41 | pos_down.resize(n); 42 | vector < T > a_down(n); 43 | cur_pos_down = 0; 44 | dfs(0, adj); 45 | decompose(0, 0, adj, a_down, values); 46 | ds_down = DS(a_down); 47 | } 48 | void update(int a, int b, T x) { 49 | while (head[a] != head[b]) { 50 | if (depth[head[a]] < depth[head[b]]) 51 | swap(a, b); 52 | ds_down.update(pos_down[head[a]], pos_down[a], x); 53 | a = parent[head[a]]; 54 | } 55 | if (depth[a] < depth[b]) 56 | swap(a, b); 57 | if (pos_down[b] + IN_EDGES > pos_down[a]) 58 | return; 59 | ds_down.update(pos_down[b] + IN_EDGES, pos_down[a], x); 60 | } 61 | void update(int a, T x) { ds_down.update(pos_down[a], x); } 62 | T query(int a, int b) { 63 | T ans; bool has = 0; 64 | while (head[a] != head[b]) { 65 | if (depth[head[a]] < depth[head[b]]) 66 | swap(a, b); 67 | ans = has ? merge(ans, ds_down.query(pos_down[head[a]], pos_down[a])) : ds_down.query(pos_down[head[a]], pos_down[a]); 68 | has = 1; 69 | a = parent[head[a]]; 70 | } 71 | if (depth[a] < depth[b]) 72 | swap(a, b); 73 | if (pos_down[b] + IN_EDGES > pos_down[a]) 74 | return ans; 75 | return has ? merge(ans, ds_down.query(pos_down[b] + IN_EDGES, pos_down[a])) : ds_down.query(pos_down[b] + IN_EDGES, pos_down[a]); 76 | } 77 | }; -------------------------------------------------------------------------------- /content/maths/fast-ntt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Same utility as FFT but with some magic primes, runs in $O(n log n)$ with better constant 3 | Posible primes and their roots: 4 | - 998244353, 3 5 | - 9223372036737335297, 3 6 | - 2013265921, 31 7 | requires binpow(be careful with overflow), and montgomery 8 | *Status:* Tested on codeforces, every prime above 9 | */ 10 | using ull = uint64_t; 11 | template 12 | struct fast_ntt { 13 | fast_ntt() {}; 14 | vector bit_sort(int n) { 15 | int h = -1; 16 | vector rev(n, 0); 17 | int skip = __lg(n) - 1; 18 | for (int i = 1; i < n; ++i) { 19 | if (!(i & (i - 1))) 20 | ++h; 21 | rev[i] = rev[i ^ (1 << h)] | (1 << (skip - h)); 22 | } 23 | return rev; 24 | } 25 | void ntt(vector& a, vector& rev, montgomery& red, ull inv_n, ull root, ull inv_root, bool invert) { 26 | int n = (int)a.size(); 27 | for (int i = 0; i < n; ++i) 28 | if (i < rev[i]) 29 | swap(a[i], a[rev[i]]); 30 | ull w = invert ? inv_root : root; 31 | vector W(n >> 1, red.transform(1)); 32 | for (int i = 1; i < (n >> 1); ++i) 33 | W[i] = red.multiply(W[i-1], w); 34 | int lim = __lg(n); 35 | for (int i = 0; i < lim; ++i) 36 | for (int j = 0; j < n; ++j) 37 | if (!(j & (1 << i))) { 38 | ull t = red.multiply(a[j ^ (1 << i)], W[(j & ((1 << i) - 1)) * (n >> (i + 1))]); 39 | a[j ^ (1 << i)] = a[j] >= t ? a[j] - t : a[j] + mod - t; 40 | a[j] = a[j] + t < mod ? a[j] + t : a[j] + t - mod; 41 | } 42 | if (invert) 43 | for (int i = 0; i < n; i++) 44 | a[i] = red.multiply(a[i], inv_n); 45 | } 46 | vector conv(vector a, vector b) { 47 | montgomery red(mod); 48 | for (auto& x : a) 49 | x = red.transform(x); 50 | for (auto& x : b) 51 | x = red.transform(x); 52 | int n = 1; 53 | while (n < a.size() || n < b.size()) 54 | n <<= 1; 55 | n <<= 1; 56 | a.resize(n); 57 | b.resize(n); 58 | ull inv_n = red.transform(bin_pow(n, mod-2, mod)); 59 | ull root = red.transform(bin_pow(gen, (mod-1)/n, mod)); 60 | ull inv_root = red.transform(bin_pow(red.reduce(root), mod-2, mod)); 61 | auto rev = bit_sort(n); 62 | ntt(a, rev, red, inv_n, root, inv_root, false); 63 | ntt(b, rev, red, inv_n, root, inv_root, false); 64 | for (int i = 0; i < n; i++) 65 | a[i] = red.multiply(a[i], b[i]); 66 | ntt(a, rev, red, inv_n, root, inv_root, true); 67 | for (auto& x : a) 68 | x = red.reduce(x); 69 | return a; 70 | } 71 | }; -------------------------------------------------------------------------------- /content/data-structures/wavelet-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Succint data structure to store strings in compressed space. It generalizes rank and select operations. Runs on $O(log sigma)$, where $sigma$ is the size of the alphabet 3 | *Status:* Tested 4 | */ 5 | template 6 | struct wavelet_tree { 7 | struct node { 8 | succinct_indexable_dictionary sid; 9 | node *ch[2]; 10 | node() = default; 11 | node(size_t len) : sid(len + 1), ch{nullptr} {} 12 | }; 13 | node *root; 14 | node *build(vector &v, vector &rbuff, int bit, int l, int r) { 15 | if (l >= r or bit == -1) return nullptr; 16 | node *_node = new node(r-l); 17 | ll left = 0, right = 0; 18 | for (ll k = l; k < r; k++) { 19 | if ((v[k] >> bit) & 1) 20 | rbuff[right++] = v[k], _node->sid.set(k - l); 21 | else v[l + left++] = v[k]; 22 | } 23 | for (int k = 0; k < right; k++) v[l + left + k] = rbuff[k]; 24 | _node->sid.build(); 25 | _node->ch[0] = build(v, rbuff, bit - 1, l, l + left); 26 | _node->ch[1] = build(v, rbuff, bit - 1, l + left, r); 27 | return _node; 28 | } 29 | wavelet_tree() = default; 30 | wavelet_tree(vector &v) { 31 | vector rbuff(v.size()); 32 | root = build(v, rbuff, MAXLOG - 1, 0, v.size()); 33 | } 34 | int rank(node *t, int l, int r, const T&x, int level) { 35 | if (l >= r or t == nullptr) return 0; 36 | if (level == -1) return r-l; 37 | bool f = (x >> level) & 1; 38 | l = t->sid.rank(f, l), r = t->sid.rank(f, r); 39 | return rank(t->ch[f], l, r, x, level-1); 40 | } 41 | int rank(const T &x, int r) { return rank(root, 0, r, x, MAXLOG-1); } 42 | T kth(node *t, int l, int r, int k, int level) { 43 | if (l >= r || t == nullptr) return 0; 44 | int cnt = t->sid.rank(false, r) - t->sid.rank(false, l); 45 | bool f = cnt <= k; 46 | l = t->sid.rank(f, l), r = t->sid.rank(f, r); 47 | if (f) return kth(t->ch[f], l, r, k - cnt, level - 1) | (T(1) << level); 48 | return kth(t->ch[f], l, r, k, level - 1); 49 | } 50 | // k-th(0-indexed) smallest number in v[l,r] 51 | T kth_smallest(int l, int r, int k) { 52 | return kth(root, l, r+1, k, MAXLOG - 1); 53 | } 54 | // k-th(0-indexed) largest number in v[l,r] 55 | T kth_largest(int l, int r, int k) { 56 | return kth(l, r, r - l - k); 57 | } 58 | int range_freq(node *t, int l, int r, T upper, int level) { 59 | if (t == nullptr || l >= r) return 0; 60 | bool f = ((upper >> level) & 1); 61 | int ret = 0; 62 | if (f) ret += t->sid.rank(false, r) - t->sid.rank(false, l); 63 | l = t->sid.rank(f, l), r = t->sid.rank(f, r); 64 | return range_freq(t->ch[f], l, r, upper, level - 1) + ret; 65 | } 66 | // count i s.t. (l <= i < r) && (v[i] < upper) 67 | int range_freq(int l, int r, T upper) { 68 | return range_freq(root, l, r, upper, MAXLOG - 1); 69 | } 70 | }; 71 | -------------------------------------------------------------------------------- /content/graphs/hopcroft-karp.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Abner Vidal 3 | *Description:* Computes maximal matching in $O (|E| dot sqrt(|V|))$, faster than Dinic. 4 | *Status:* Tested on CSES 5 | */ 6 | struct hopcroft_karp { 7 | const int INF = 1e9; 8 | int n; vector l, r, d, ptr, g_edges, g_start, q; 9 | int q_h, q_t; 10 | HopcroftKarp(int _n, const vector>& adj) : n(_n) { 11 | l.assign(2*n+1, 0); r.assign(2*n+1, 0); d.assign(2*n+1, 0); ptr.assign(2*n+1, 0); 12 | g_start.resize(n+2); q.resize(n+10); q_h = q_t = 0; 13 | for (int u = 1; u <= n; u++) { 14 | g_start[u] = g_edges.size(); 15 | for (int b : adj[u]) g_edges.push_back(b+n); 16 | } 17 | g_start[n+1] = g_edges.size(); 18 | } 19 | bool bfs() { 20 | q_h = q_t = 0; 21 | for (int u = 1; u <= n; u++) { 22 | if (!l[u]) { d[u] = 0; q[q_t++] = u; } 23 | else d[u] = INF; 24 | } 25 | d[0] = INF; 26 | while (q_h < q_t) { 27 | int u = q[q_h++]; 28 | for (int i = g_start[u]; i < g_start[u+1]; i++) { 29 | int v = g_edges[i], nxt = r[v]; 30 | if (d[nxt] == INF) { 31 | d[nxt] = d[u]+1; 32 | if (nxt) q[q_t++] = nxt; 33 | else d[0] = d[u]+1; 34 | } 35 | } 36 | } 37 | return d[0] != INF; 38 | } 39 | bool dfs(int u) { 40 | vector> st; 41 | int i = ptr[u]; 42 | int u_start = g_start[u]; 43 | int u_end = g_start[u+1]; 44 | while (true) { 45 | if (i < u_end-u_start) { 46 | int v = g_edges[u_start+i]; 47 | int nxt = r[v]; 48 | if (!nxt) { 49 | l[u] = v; r[v] = u; ptr[u] = i+1; 50 | while (!st.empty()) { 51 | auto [pu, pi] = st.back(); st.pop_back(); 52 | int pv = g_edges[g_start[pu]+pi]; 53 | l[pu] = pv; r[pv] = pu; ptr[pu] = pi+1; 54 | } 55 | return true; 56 | } else if (d[nxt] == d[u]+1) { 57 | st.push_back({u, i}); u = nxt; i = ptr[u]; 58 | u_start = g_start[u]; u_end = g_start[u+1]; 59 | } else i++; 60 | } else { 61 | d[u] = INF; 62 | if (st.empty()) return false; 63 | auto [pu, pi] = st.back(); st.pop_back(); 64 | u = pu; i = pi+1; ptr[u] = i; 65 | u_start = g_start[u]; u_end = g_start[u+1]; 66 | } 67 | } 68 | } 69 | int maximum_matching(int want) { 70 | int match = 0; 71 | for (int u = 1; u <= n && match < want; u++) { 72 | if (!l[u]) { 73 | for (int i = g_start[u]; i < g_start[u+1]; i++) { 74 | int v = g_edges[i]; 75 | if (!r[v]) { l[u] = v; r[v] = u; match++; break; } 76 | } 77 | } 78 | } 79 | while (match < want && bfs()) { 80 | for (int u = 1; u <= n; u++) ptr[u] = 0; 81 | for (int u = 1; u <= n && match < want; u++) 82 | if (!l[u] && dfs(u)) match++; 83 | } 84 | return match; 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /content/data-structures/lct.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Represents a forest of unrooted trees. You can add and remove edges (as long as the result is still a forest), and check whether two nodes are in the same tree. Runs on $O(log n)$ per operation. 3 | *Status:* Tested 4 | */ 5 | struct Node { // Splay tree. Root's pp contains tree's parent. 6 | Node *p = 0, *pp = 0, *c[2]; 7 | bool flip = 0; 8 | Node() { c[0] = c[1] = 0; fix(); } 9 | void fix() { 10 | if (c[0]) c[0]->p = this; 11 | if (c[1]) c[1]->p = this; 12 | // (+ update sum of subtree elements etc. if wanted) 13 | } 14 | void pushFlip() { 15 | if (!flip) return; 16 | flip = 0; swap(c[0], c[1]); 17 | if (c[0]) c[0]->flip ^= 1; 18 | if (c[1]) c[1]->flip ^= 1; 19 | } 20 | int up() { return p ? p->c[1] == this : -1; } 21 | void rot(int i, int b) { 22 | int h = i ^ b; 23 | Node *x = c[i], *y = b == 2 ? x : x->c[h], *z = b ? y : x; 24 | if ((y->p = p)) p->c[up()] = y; 25 | c[i] = z->c[i ^ 1]; 26 | if (b < 2) { 27 | x->c[h] = y->c[h ^ 1]; 28 | z->c[h ^ 1] = b ? x : this; 29 | } 30 | y->c[i ^ 1] = b ? this : x; 31 | fix(); x->fix(); y->fix(); 32 | if (p) p->fix(); swap(pp, y->pp); 33 | } 34 | void splay() { /// Splay this up to the root. Always finishes without flip set. 35 | for (pushFlip(); p;) { 36 | if (p->p) p->p->pushFlip(); 37 | p->pushFlip(); pushFlip(); 38 | int c1 = up(), c2 = p->up(); 39 | if (c2 == -1) p->rot(c1, 2); 40 | else p->p->rot(c2, c1 != c2); 41 | } 42 | } 43 | Node *first() { /// Return the min element of the subtree rooted at this, splayed to the top. 44 | pushFlip(); 45 | return c[0] ? c[0]->first() : (splay(), this); 46 | } 47 | }; 48 | struct link_cut { 49 | vector node; 50 | link_cut(int N) : node(N) {} 51 | void link(int u, int v) { // add an edge (u, v) 52 | makeRoot(&node[u]); 53 | node[u].pp = &node[v]; 54 | } 55 | void cut(int u, int v) { // remove an edge (u, v) 56 | Node *x = &node[u], *top = &node[v]; 57 | makeRoot(top); 58 | x->splay(); 59 | assert(top == (x->pp ?: x->c[0])); 60 | if (x->pp) x->pp = 0; 61 | else { 62 | x->c[0] = top->p = 0; 63 | x->fix(); 64 | } 65 | } 66 | bool connected(int u, int v) { 67 | Node *nu = access(&node[u])->first(); 68 | return nu == access(&node[v])->first(); 69 | } 70 | void makeRoot(Node *u) { 71 | access(u); u->splay(); 72 | if (u->c[0]) { 73 | u->c[0]->p = 0; u->c[0]->flip ^= 1; 74 | u->c[0]->pp = u; u->c[0] = 0; 75 | u->fix(); 76 | } 77 | } 78 | Node *access(Node *u) { 79 | u->splay(); 80 | while (Node *pp = u->pp) { 81 | pp->splay(); u->pp = 0; 82 | if (pp->c[1]) { 83 | pp->c[1]->p = 0; 84 | pp->c[1]->pp = pp; 85 | } 86 | pp->c[1] = u; 87 | pp->fix(); u = pp; 88 | } 89 | return u; 90 | } 91 | }; -------------------------------------------------------------------------------- /content/maths/fft.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* FFT(a) computes $ hat(f(k)) = sum_x a[x] exp(2 pi i dot k x \/ N)$ for all $k$. $N$ must be a power of 2, runs on $O(N log N)$, where $N = |A| + |B|$ 3 | - For convolution of complex numbers or more than two vectors: FFT, multiply pointwise, divide by $n$, reverse(start+1, end), FFT back. 4 | - Rounding is safe if $(sum a_i^2 + sum b_i^2)log_2(N) < 9 dot 10^14$ (in practice $10^16$; higher for random inputs). 5 | *Status:* Highly tested (josupo.jp) 6 | */ 7 | struct FFT { 8 | const long double PI = acos(-1); 9 | typedef long double d; // to double if too slow 10 | void fft(vector> &a) { 11 | int n = a.size(), L = 31 - __builtin_clz(n); 12 | vector> R(2, 1), rt(2, 1); 13 | for (int k = 2; k < n; k *= 2) { 14 | R.resize(n); rt.resize(n); 15 | auto x = polar(1.0L, PI / k); 16 | for(int i = k; i < 2*k; ++i) rt[i] = R[i] = i & 1 ? R[i / 2] * x : R[i / 2]; 17 | } 18 | vector rev(n); 19 | for(int i = 0; i < n; ++i) rev[i] = (rev[i / 2] | (i & 1) << L) / 2; 20 | for(int i = 0; i < n; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]); 21 | for (int k = 1; k < n; k *= 2) 22 | for (int i = 0; i < n; i += 2 * k) 23 | for(int j = 0; j < k; ++j) { 24 | auto x = (d*)&rt[j + k], y = (d*)&a[i + j + k]; 25 | complex z(x[0]*y[0] - x[1]*y[1], x[0]*y[1] + x[1]*y[0]); 26 | a[i + j + k] = a[i + j] - z, a[i + j] += z; 27 | } 28 | } 29 | vector conv(vector &a, vector &b) { 30 | if (a.empty() || b.empty()) return {}; 31 | vector res(a.size() + b.size() - 1); 32 | int B = 32 - __builtin_clz(res.size()), n = 1 << B; 33 | vector> in(n), out(n); 34 | copy(a.begin(), a.end(), in.begin()); 35 | for(int i = 0; i < b.size(); ++i) in[i].imag(b[i]); 36 | fft(in); for (auto &x : in) x *= x; 37 | for(int i = 0; i < n; ++i) out[i] = in[-i & (n - 1)] - conj(in[i]); 38 | fft(out); for(int i = 0; i < res.size(); ++i) res[i] = imag(out[i]) / (4 * n); 39 | vector resint(res.size()); 40 | for (int i = 0; i < res.size(); i++) resint[i] = round(res[i]); 41 | return resint; 42 | } 43 | vector convMod(vector &a, vector &b, int mod) { 44 | if (a.empty() || b.empty()) return {}; 45 | vector res(a.size() + b.size() - 1); 46 | int B = 32 - __builtin_clz(res.size()), n = 1 << B, cut = int(sqrt(mod)); 47 | vector> L(n), R(n), outs(n), outl(n); 48 | for (int i = 0; i < a.size(); i++) L[i] = complex(a[i]/cut, a[i]%cut); 49 | for (int i = 0; i < b.size(); i++) R[i] = complex(b[i]/cut, b[i]%cut); 50 | fft(L), fft(R); 51 | for (int i = 0; i < n; i++) { 52 | int j = -i & (n-1); 53 | outl[j] = (L[i] + conj(L[j])) * R[i] / ((d)2.0 * n); 54 | outs[j] = (L[i] - conj(L[j])) * R[i] / ((d)2.0 * n) / complex(0, 1); 55 | } 56 | fft(outl), fft(outs); 57 | for (int i = 0; i < res.size(); i++) { 58 | int av = (int)(real(outl[i])+.5), cv = (int)(imag(outs[i])+.5); 59 | int bv = (int)(imag(outl[i])+.5) + (int)(real(outs[i])+.5); 60 | res[i] = ((av % mod * cut + bv) % mod * cut + cv) % mod; 61 | } 62 | vector resint(res.size()); 63 | for (int i = 0; i < res.size(); i++) resint[i] = round(res[i]); 64 | return resint; 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /content/dynamic-programming/li-chao-segment.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Dynamically insert lines of the form y = a*x + b and query for the minimum value at any x in a fixed interval [L, R]. 3 | *Status:* Tested on CSES 4 | */ 5 | using ll = long long; 6 | const ll inf = 2e18; 7 | struct Line { 8 | ll m, c; 9 | ll eval(ll x) { 10 | return m * x + c; 11 | } 12 | }; 13 | struct node { 14 | Line line; 15 | node* left = nullptr; 16 | node* right = nullptr; 17 | node(Line line) : line(line) {} 18 | void add_segment(Line nw, int l, int r, int L, int R) { 19 | if (l > r || r < L || l > R) return; 20 | int m = (l + 1 == r ? l : (l + r) / 2); 21 | if (l >= L and r <= R) { 22 | bool lef = nw.eval(l) < line.eval(l); 23 | bool mid = nw.eval(m) < line.eval(m); 24 | if (mid) swap(line, nw); 25 | if (l == r) return; 26 | if (lef != mid) { 27 | if (left == nullptr) left = new node(nw); 28 | else left -> add_segment(nw, l, m, L, R); 29 | } 30 | else { 31 | if (right == nullptr) right = new node(nw); 32 | else right -> add_segment(nw, m + 1, r, L, R); 33 | } 34 | return; 35 | } 36 | if (max(l, L) <= min(m, R)) { 37 | if (left == nullptr) left = new node({0, inf}); 38 | left -> add_segment(nw, l, m, L, R); 39 | } 40 | if (max(m + 1, L) <= min(r, R)) { 41 | if (right == nullptr) right = new node ({0, inf}); 42 | right -> add_segment(nw, m + 1, r, L, R); 43 | } 44 | } 45 | ll query_segment(ll x, int l, int r, int L, int R) { 46 | if (l > r || r < L || l > R) return inf; 47 | int m = (l + 1 == r ? l : (l + r) / 2); 48 | if (l >= L and r <= R) { 49 | ll ans = line.eval(x); 50 | if (l < r) { 51 | if (x <= m && left != nullptr) ans = min(ans, left -> query_segment(x, l, m, L, R)); 52 | if (x > m && right != nullptr) ans = min(ans, right -> query_segment(x, m + 1, r, L, R)); 53 | } 54 | return ans; 55 | } 56 | ll ans = inf; 57 | if (max(l, L) <= min(m, R)) { 58 | if (left == nullptr) left = new node({0, inf}); 59 | ans = min(ans, left -> query_segment(x, l, m, L, R)); 60 | } 61 | if (max(m + 1, L) <= min(r, R)) { 62 | if (right == nullptr) right = new node ({0, inf}); 63 | ans = min(ans, right -> query_segment(x, m + 1, r, L, R)); 64 | } 65 | return ans; 66 | } 67 | }; 68 | struct LiChaoTree { 69 | int L, R; 70 | node* root; 71 | LiChaoTree() : L(numeric_limits::min() / 2), R(numeric_limits::max() / 2), root(nullptr) {} 72 | LiChaoTree(int L, int R) : L(L), R(R) { 73 | root = new node({0, inf}); 74 | } 75 | void add_line(Line line) { 76 | root -> add_segment(line, L, R, L, R); 77 | } 78 | // y = mx + b: x in [l, r] 79 | void add_segment(Line line, int l, int r) { 80 | root -> add_segment(line, L, R, l, r); 81 | } 82 | ll query(ll x) { 83 | return root -> query_segment(x, L, R, L, R); 84 | } 85 | ll query_segment(ll x, int l, int r) { 86 | return root -> query_segment(x, l, r, L, R); 87 | } 88 | }; -------------------------------------------------------------------------------- /content/data-structures/kd-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* given an array of $n$ points, it answers the minimum manhattan distance from the query point in $O(3^{d}log(n))$ 3 | *Status:* Tested on CSES 4 | */ 5 | template 6 | struct pt { 7 | array p; 8 | bool operator!=(const pt &o) const { return p != o.p; } 9 | T dist(const pt &o) const { 10 | T res = 0; 11 | for (int i = 0; i < d; i++) 12 | res += abs(p[i] - o.p[i]); 13 | return res; 14 | } 15 | }; 16 | template 17 | struct kd_tree { 18 | struct node { 19 | int ax; T val; pt p; 20 | node *izq, *der; 21 | array mn, mx; 22 | }; 23 | node *root; 24 | T mn_dist(const pt &q, const array & mnb, const array &mxb) { 25 | T dist = 0; 26 | for (int i = 0; i < d; i++) { 27 | if (q.p[i] < mnb[i]) dist += mnb[i]-q.p[i]; 28 | else if (q.p[i] > mxb[i]) dist += q.p[i]-mxb[i]; 29 | } 30 | return dist; 31 | } 32 | node *build_tree(vector &a, int l, int r) { 33 | if (l > r) return nullptr; 34 | node *cur = new node(); 35 | array minb, maxb; 36 | for (int i = 0; i < d; i++) { 37 | minb[i] = a[l].p[i]; 38 | maxb[i] = a[l].p[i]; 39 | } 40 | for (int j = l + 1; j <= r; j++) { 41 | for (int i = 0; i < d; i++) { 42 | if (a[j].p[i] < minb[i]) minb[i] = a[j].p[i]; 43 | if (a[j].p[i] > maxb[i]) maxb[i] = a[j].p[i]; 44 | } 45 | } 46 | cur->mn = minb; cur->mx = maxb; int ax = 0; 47 | T mxld = 0; 48 | for (int i = 0; i < d; i++) { 49 | T ld = maxb[i]-minb[i]; 50 | if (ld > mxld) { 51 | mxld = ld; 52 | ax = i; 53 | } 54 | } 55 | cur->ax = ax; int mid = (l+r)/2; 56 | nth_element(a.begin() + l, a.begin() + mid, a.begin() + r + 1, [ax](const pt &x, const pt &y) { 57 | return x.p[ax] < y.p[ax]; 58 | }); 59 | cur->p = a[mid]; cur->val = a[mid].p[ax]; 60 | cur->izq = build_tree(a, l, mid - 1); 61 | cur->der = build_tree(a, mid + 1, r); 62 | return cur; 63 | } 64 | kd_tree(vector &a) { 65 | root = build_tree(a, 0, a.size() - 1); 66 | } 67 | void query(node *cur, const pt &q, T &ans) { 68 | if (cur == nullptr) return; 69 | if (q != cur->p) { 70 | T d_here = q.dist(cur->p); 71 | if (d_here < ans) 72 | ans = d_here; 73 | } else { 74 | ans = min(ans, (T)0); 75 | } 76 | vector> ch; 77 | if (cur->izq) { 78 | T d_izq = mn_dist(q, cur->izq->mn, cur->izq->mx); 79 | ch.push_back({d_izq, cur->izq}); 80 | } 81 | if (cur->der) { 82 | T d_der = mn_dist(q, cur->der->mn, cur->der->mx); 83 | ch.push_back({d_der, cur->der}); 84 | } 85 | sort(ch.begin(), ch.end(), [](const auto &a, const auto &b) { 86 | return a.first < b.first; 87 | }); 88 | for (auto &[d_val, to] : ch) 89 | if (d_val < ans) query(to, q, ans); 90 | } 91 | T query(const pt &q) { 92 | T ans = numeric_limits::max(); 93 | query(root, q, ans); 94 | return ans; 95 | } 96 | }; 97 | -------------------------------------------------------------------------------- /content/graphs/dominator-tree.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Computes the inmediate dominator of every node in a directed graph in O((|E|+|V|)log(|V|)). 3 | *Status:* Tested on CSES 4 | */ 5 | struct dominator_tree { 6 | int n,l,s; 7 | vector tin,par,vis_ord, dsu_mn, dsu_par, sdom, dep,rdom,idom; 8 | vector vis; 9 | vector> up; 10 | vector>> up_mn; 11 | void dfs(int u, int p, vector> & adj){ 12 | if (vis[u]) return; 13 | vis[u] = 1; 14 | dep[u] = dep[p]+1; 15 | tin[u] = vis_ord.size(); 16 | vis_ord.push_back(u); 17 | par[u] = p; 18 | for (int v : adj[u]) dfs(v,u,adj); 19 | } 20 | int find(int x){ 21 | if (dsu_par[x] == -1) return x; 22 | if (dsu_par[dsu_par[x]] != -1){ 23 | int res = find(dsu_par[x]); 24 | if (tin[res] < tin[dsu_mn[x]]) 25 | dsu_mn[x] = res; 26 | dsu_par[x] = dsu_par[dsu_par[x]]; 27 | } 28 | assert(dsu_mn[x] != INT32_MAX); 29 | return dsu_mn[x]; 30 | } 31 | void get_sdom(vector> & rev){ 32 | for (int i = vis_ord.size()-1; i >= 0; i--){ 33 | int c = vis_ord[i]; 34 | if (c == s) continue; 35 | for (int to : rev[c]){ 36 | int res = find(to); 37 | if (sdom[c] == -1 || tin[res] < tin[sdom[c]]) 38 | sdom[c] = res; 39 | } 40 | dsu_par[c] = par[c]; 41 | dsu_mn[c] = sdom[c]; 42 | if (sdom[c] == -1) cerr << c << endl; 43 | } 44 | } 45 | void init_up(){ 46 | for (int i = 0; i < n; i++){ 47 | if (!vis[i]) continue; 48 | up[i][0] = par[i]; 49 | up_mn[i][0] = {tin[sdom[i]],i}; 50 | } 51 | for (int i = 1; i < l; i++) { 52 | for (int j = 0; j < n; j++) { 53 | if (!vis[j]) continue; 54 | int h = up[j][i-1]; 55 | if (h == -1) { 56 | up[j][i] = -1; 57 | up_mn[j][i] = up_mn[j][i-1]; 58 | } else { 59 | up[j][i] = up[h][i-1]; 60 | up_mn[j][i] = min(up_mn[j][i-1], up_mn[h][i-1]); 61 | } 62 | } 63 | } 64 | } 65 | int get_min(int v, int u){ 66 | int dist = dep[u]-dep[v]; 67 | pair ret = up_mn[u][0]; 68 | int w = u; 69 | for (int i = 0; i < l; i++) 70 | if (dist&(1<> & adj, vector> & rev, int _s = 0, int logn = 20){ 87 | n = adj.size(); l = logn; s = _s; 88 | tin.resize(n,INT32_MAX); 89 | par.resize(n,-1); 90 | vis.resize(n,0); 91 | dep.resize(n,0); 92 | dfs(s,-1,adj); 93 | dsu_par.resize(n,-1); 94 | dsu_mn.resize(n,INT32_MAX); 95 | sdom.resize(n,-1); 96 | rdom.resize(n,-1); 97 | idom.resize(n,-1); 98 | get_sdom(rev); 99 | up.assign(n,vector(logn)); 100 | up_mn.assign(n,vector>(logn)); 101 | init_up(); 102 | get_idom(); 103 | } 104 | }; -------------------------------------------------------------------------------- /content/data-structures/treap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* A short self-balancing tree. It acts as a sequential container with log-time splits/joins, and is easy to augment with additional data. 3 | *Status:* Tested 4 | */ 5 | struct treap { 6 | static mt19937_64 MT; 7 | struct node { 8 | node *left, *right; ll key, priority, value, max_value; 9 | node(ll k, ll v = 0) { 10 | left = right = NULL; key = k; priority = MT(); 11 | max_value = value = v; 12 | } 13 | }; 14 | ll value(node* T) { return T ? T->value : -INF; } 15 | ll max_value(node* T) { return T ? T->max_value : -INF; } 16 | void update(node* T) { 17 | T->max_value = max({T->value, max_value(T->left), max_value(T->right)});} 18 | node *root; 19 | void merge(node* &T, node* T1, node* T2) { 20 | if(T1 == NULL) { T = T2; return; } 21 | if(T2 == NULL) { T = T1; return; } 22 | if(T1->priority > T2->priority) 23 | merge(T1->right, T1->right, T2), T = T1; 24 | else merge(T2->left, T1, T2->left), T = T2; 25 | return update(T); 26 | } 27 | void merge(node* &T, node* T1, node* T2, node* T3) { 28 | merge(T, T1, T2); merge(T, T, T3); 29 | } 30 | void split(node* T, ll x, node* &T1, node* &T2) { 31 | if(T == NULL) { T1 = T2 = NULL; return; } 32 | if(T->key <= x) { split(T->right, x, T->right, T2); T1 = T; } 33 | else { split(T->left, x, T1, T->left); T2 = T; } 34 | return update(T); 35 | } 36 | void split(node* T, ll x, ll y, node* &T1, node* &T2, node* &T3) { 37 | split(T, x-1, T1, T2); split(T2, y, T2, T3); 38 | } 39 | bool search(node* T, ll x) { 40 | if(T == NULL) return false; if(T->key == x) return true; 41 | if(x < T->key) return search(T->left, x); 42 | return search(T->right, x); 43 | } 44 | void insert(node* &T, node* n) { 45 | if(T == NULL) { T = n; return; } 46 | if(n->priority > T->priority) { 47 | split(T, n->key, n->left, n->right); T = n; 48 | } else if(n->key < T->key) insert(T->left, n); 49 | else insert(T->right, n); 50 | return update(T); 51 | } 52 | void erase(node* &T, ll x) { 53 | if(T == NULL) return; 54 | if(T->key == x) { merge(T, T->left, T->right); } 55 | else if(x < T->key) erase(T->left, x); 56 | else erase(T->right, x); 57 | return update(T); 58 | } 59 | bool set(node* T, ll k, ll v) { 60 | if(T == NULL) return false; 61 | bool found; 62 | if(T->key == k) T->value = k, found = true; 63 | else if(k < T->key) found = set(T->left, k, v); 64 | else found = set(T->right, k, v); 65 | if(found) update(T); return found; 66 | } 67 | node* find(node* T, ll k) { 68 | if(T == NULL) return NULL; 69 | if(T->key == k) return T; 70 | if(k < T->key) return find(T->left, k); 71 | return find(T->right, k); 72 | } 73 | treap() {root = NULL;} 74 | treap(ll x) {root = new node(x);} 75 | treap &merge(treap &O) {merge(root, root, O.root); return *this; } 76 | treap split(ll x) {treap ans; split(root, x, root, ans.root); return ans; } 77 | bool search(ll x) {return search(root, x); } 78 | void insert(ll x) {if(search(root, x)) return; return insert(root, new node(x));} 79 | void erase(ll x) {return erase(root, x); } 80 | void set(ll k, ll v) {if(set(root, k, v)) return; insert(root, new node(k, v));} 81 | ll operator[](ll k) { 82 | node* n = find(root, k); 83 | if(n == NULL) n = new node(k), insert(root, n); return n->value; 84 | } 85 | ll query(ll a, ll b) { 86 | node *T1, *T2, *T3; split(root, a, b, T1, T2, T3); 87 | ll ans = max_value(T2); merge(root, T1, T2, T3); 88 | return ans; 89 | } 90 | }; 91 | mt19937_64 treap::MT(chrono::system_clock::now().time_since_epoch().count()); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📚 USM Competitive Programming Handbook 2 | 3 | A comprehensive collection of algorithms and data structures for competitive programming, maintained by Universidad Técnica Federico Santa María (USM) students. 4 | 5 | ## 🚀 Quick Start 6 | 7 | ### Prerequisites 8 | - [Typst](https://typst.app/) - A modern markup-based typesetting system 9 | 10 | ### Compilation 11 | ```bash 12 | typst compile main.typ 13 | ``` 14 | 15 | This generates a PDF handbook with all algorithms organized by category. 16 | 17 | ## 📖 Contents 18 | 19 | The handbook includes implementations for: 20 | 21 | - **🔧 General** - Templates and troubleshooting guides 22 | - **🔤 Strings** - String processing algorithms (KMP, Z-algorithm, Suffix Array, Trie, etc.) 23 | - **⚡ Algorithms** - General algorithms (Mo's algorithm, Tortoise-Hare cycle detection) 24 | - **📊 Data Structures** - Advanced data structures (Segment Trees, Fenwick Trees, Treaps, etc.) 25 | - **🧮 Mathematics** - Number theory, linear algebra, and polynomial operations 26 | - **📈 Graphs** - Graph algorithms (DFS, BFS, Shortest paths, Network flows, etc.) 27 | - **📐 Geometry** - Computational geometry (Convex Hull, Point operations, etc.) 28 | - **🎯 Dynamic Programming** - DP optimizations and classic problems 29 | - **🔀 Combinatorics** - Advanced combinatorial algorithms 30 | 31 | ## 📝 Contributing Guidelines 32 | 33 | ### Code Style 34 | - **Naming**: Use lowercase with hyphens for folders and files (`knuth-morris-pratt` → `kmp`) 35 | - **File Extensions**: Only `.cpp` and `.typ` files allowed 36 | - **Indentation**: Use exactly **2 spaces** (no tabs) 37 | - **Length**: Keep filenames under 18 characters when possible 38 | - **Atomicity**: Each file should contain only one algorithm/data structure 39 | 40 | ### Code Requirements 41 | - **Documentation**: Every C++ file must start with a multi-line comment describing the algorithm 42 | - **No Macros**: Avoid competitive programming macros like `rep`, `repx`, etc. 43 | - **Clean Code**: Write readable, well-structured code 44 | 45 | ### File Structure 46 | ``` 47 | content/ 48 | ├── algorithms/ # General algorithms 49 | ├── combinatorial/ # Combinatorial algorithms 50 | ├── data-structures/ # Advanced data structures 51 | ├── dynamic-programming/ # DP techniques 52 | ├── general/ # Templates and utilities 53 | ├── geometry/ # Computational geometry 54 | ├── graphs/ # Graph algorithms 55 | ├── maths/ # Mathematical algorithms 56 | └── strings/ # String algorithms 57 | ``` 58 | 59 | ## 🎯 Project Goals 60 | 61 | 1. **Concise Implementations** - Provide short, efficient algorithm implementations 62 | 2. **Educational Value** - Include clear descriptions and explanations 63 | 3. **Competitive Ready** - Code optimized for programming contests 64 | 4. **Comprehensive Coverage** - Cover all essential competitive programming topics 65 | 66 | ## 🚧 Roadmap 67 | 68 | - [ ] Additional dynamic programming techniques 69 | - [ ] Voronoi diagrams and Delaunay triangulation 70 | - [ ] Extended geometry primitives (lines, circles, 3D operations) 71 | - [ ] 3D Convex Hull algorithms 72 | - [ ] Karatsuba polynomial multiplication 73 | - [ ] Advanced polynomial operations 74 | 75 | ## 👥 Team 76 | 77 | **Maintainers:** 78 | - Gabriel Carmona (MrYhatoh) 79 | - Carlos Lagos (CharlesLakes) 80 | - Sebastián Torrealba (storrealbac) 81 | - Abner Vidal (abner_vidal) 82 | 83 | **Contributors:** 84 | - Javier Oliva (JOliva) 85 | - Marcelo Lemus (MarceloL) 86 | 87 | ## 📄 License 88 | 89 | This project is licensed under the terms specified in the [LICENSE](LICENSE) file. 90 | 91 | --- 92 | 93 | *Built with ❤️ for the competitive programming community at USM* 94 | -------------------------------------------------------------------------------- /content/graphs/ahld.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Author:* Javier Oliva 3 | *Description:* Same complexity of HLD, but with worst constant. This implementation only uses asociativity 4 | *Status:* Partially tested 5 | */ 6 | template < class DS, class T, T merge(T, T), int IN_EDGES > 7 | struct associative_heavy_light { 8 | vector parent, depth, heavy, head, pos_up, pos_down; 9 | int n, cur_pos_up, cur_pos_down; 10 | DS ds_up, ds_down; 11 | int dfs(int v, vector < vector < int >> 12 | const & adj) { 13 | int size = 1; 14 | int max_c_size = 0; 15 | for (int c: adj[v]) 16 | if (c != parent[v]) { 17 | parent[c] = v, depth[c] = depth[v] + 1; 18 | int c_size = dfs(c, adj); 19 | size += c_size; 20 | if (c_size > max_c_size) 21 | max_c_size = c_size, heavy[v] = c; 22 | } 23 | return size; 24 | } 25 | void decompose(int v, int h, vector < vector < int >> 26 | const & adj, vector < T > & a_up, vector < T > & a_down, vector < T > & values) { 27 | head[v] = h, pos_up[v] = cur_pos_up--, pos_down[v] = cur_pos_down++; 28 | a_up[pos_up[v]] = values[v]; 29 | a_down[pos_down[v]] = values[v]; 30 | if (heavy[v] != -1) 31 | decompose(heavy[v], h, adj, a_up, a_down, values); 32 | for (int c: adj[v]) { 33 | if (c != parent[v] && c != heavy[v]) 34 | decompose(c, c, adj, a_up, a_down, values); 35 | } 36 | } 37 | associative_heavy_light(vector < vector < int > > 38 | const & adj, vector < T > & values) { 39 | n = adj.size(); parent.resize(n); 40 | depth.resize(n); heavy.resize(n, -1); 41 | head.resize(n); pos_up.resize(n); 42 | pos_down.resize(n); 43 | vector a_up(n), a_down(n); 44 | cur_pos_up = n - 1; 45 | cur_pos_down = 0; 46 | dfs(0, adj); 47 | decompose(0, 0, adj, a_up, a_down, values); 48 | ds_up = DS(a_up); 49 | ds_down = DS(a_down); 50 | } 51 | void update(int a, int b, T x) { 52 | while (head[a] != head[b]) { 53 | if (depth[head[a]] < depth[head[b]]) 54 | swap(a, b); 55 | ds_up.update(pos_up[a], pos_up[head[a]], x); 56 | ds_down.update(pos_down[head[a]], pos_down[a], x); 57 | a = parent[head[a]]; 58 | } 59 | if (depth[a] < depth[b]) 60 | swap(a, b); 61 | if (pos_up[a] > pos_up[b] - IN_EDGES) 62 | return; 63 | ds_up.update(pos_up[a], pos_up[b] - IN_EDGES, x); 64 | ds_down.update(pos_down[b] + IN_EDGES, pos_down[a], x); 65 | } 66 | void update(int a, T x) { 67 | ds_up.update(pos_up[a], x); 68 | ds_down.update(pos_down[a], x); 69 | } 70 | T query(int a, int b) { 71 | T ansL, ansR; 72 | bool hasL = 0, hasR = 0; 73 | while (head[a] != head[b]) { 74 | if (depth[head[a]] > depth[head[b]]) { 75 | hasL ? ansL = merge(ansL, ds_up.query(pos_up[a], pos_up[head[a]])) : ansL = ds_up.query(pos_up[a], pos_up[head[a]]), hasL = 1; 76 | a = parent[head[a]]; 77 | } else { 78 | hasR ? ansR = merge(ds_down.query(pos_down[head[b]], pos_down[b]), ansR) : ansR = ds_down.query(pos_down[head[b]], pos_down[b]), hasR = 1; 79 | b = parent[head[b]]; 80 | } 81 | } 82 | if (depth[a] > depth[b] && pos_up[a] <= pos_up[b] - IN_EDGES) 83 | hasL ? ansL = merge(ansL, ds_up.query(pos_up[a], pos_up[b] - IN_EDGES)) : ansL = ds_up.query(pos_up[a], pos_up[b] - IN_EDGES), hasL = 1; 84 | else if (depth[a] <= depth[b] && pos_down[a] + IN_EDGES <= pos_down[b]) 85 | hasR ? ansR = merge(ds_down.query(pos_down[a] + IN_EDGES, pos_down[b]), ansR) : ansR = ds_down.query(pos_down[a] + IN_EDGES, pos_down[b]), hasR = 1; 86 | 87 | return (!hasL) ? ansR : (!hasR ? ansL : merge(ansL, ansR)); 88 | } 89 | }; -------------------------------------------------------------------------------- /tracker.yaml: -------------------------------------------------------------------------------- 1 | content: 2 | - general: 3 | - template.cpp 4 | - troubleshoot.typ 5 | - hash.typ 6 | - strings: 7 | - rolling-hashing.cpp 8 | - k-rolling-hashing.cpp 9 | - kmp.cpp 10 | - z.cpp 11 | - manacher.cpp 12 | - trie.cpp 13 | - suffix-array.cpp 14 | - suffix-automaton.cpp 15 | - min-rotation.cpp 16 | - aho-corasick.cpp 17 | - algorithms: 18 | - tortoise-hare.cpp 19 | - mo.cpp 20 | - mo-rollback.cpp 21 | - mo-update.cpp 22 | - data-structures: 23 | - min-queue.cpp 24 | - min-stack.cpp 25 | - min-deque.cpp 26 | 27 | - bit-vector.cpp 28 | - union-find.cpp 29 | - union-find-rollback.cpp 30 | 31 | - sparse-table.cpp 32 | - disjoint-sparse-table.cpp 33 | - range-query-constant.cpp 34 | 35 | - segment-tree.cpp 36 | - segment-tree-with-walk.cpp 37 | - segment-tree-lazy.cpp 38 | - iterative-segment-tree-lazy.cpp 39 | - persistent-segment-tree.cpp 40 | - dynamic-segment-tree.cpp 41 | - extended-segment-tree.cpp 42 | - query-tree.cpp 43 | - sqrt-decomposition.cpp 44 | - merge-sort-tree.cpp 45 | 46 | - ordered-set.cpp 47 | 48 | - bit.cpp 49 | - bit-2d.cpp 50 | 51 | - treap.cpp 52 | - implicit-treap.cpp 53 | 54 | - lct.cpp 55 | - succinct-indexable-dictionary.cpp 56 | - wavelet-tree.cpp 57 | - line-container.cpp 58 | - kd-tree.cpp 59 | - maths: 60 | - mulmod.cpp 61 | - fraction.cpp 62 | 63 | - binary-pow.cpp 64 | - binary-pow-128-bits.cpp 65 | - binary-pow-mulmod.cpp 66 | - tetration.cpp 67 | - montgomery.cpp 68 | 69 | - extended-gcd.cpp 70 | - crt.cpp 71 | 72 | - prime-factors.cpp 73 | - counting-divisors.cpp 74 | - divisors.cpp 75 | 76 | - discrete-log.cpp 77 | 78 | - erathostenes-sieve.cpp 79 | 80 | - euler-phi.cpp 81 | - euler-phi-sieve.cpp 82 | 83 | - mobius-sieve.cpp 84 | 85 | - factorial.cpp 86 | 87 | - fft.cpp 88 | - ntt.cpp 89 | - fast-ntt.cpp 90 | - fwht.cpp 91 | - poly-shift.cpp 92 | - sieveking-kung.cpp 93 | - non-deterministic-miller-rabin.cpp 94 | - miller-rabin.cpp 95 | - pollard-rho.cpp 96 | - fast-prime-factorization.cpp 97 | - lagrange-point.cpp 98 | 99 | - gauss.cpp 100 | - xor-basis.cpp 101 | - simplex.cpp 102 | - matrix.cpp 103 | 104 | - graphs: 105 | - dfs.cpp 106 | - bfs.cpp 107 | - floyd-warshall.cpp 108 | - dijkstra.cpp 109 | - kruskal.cpp 110 | - bridges.cpp 111 | - dinic.cpp 112 | - hopcroft-karp.cpp 113 | - mfed.cpp 114 | - articulation-points.cpp 115 | - dominator-tree.cpp 116 | - hld.cpp 117 | - ahld.cpp 118 | - eppstein.cpp 119 | - hungarian.cpp 120 | - kosaraju.cpp 121 | - lca.cpp 122 | - lca-rmq.cpp 123 | - centroid-decomposition.cpp 124 | - bellman-ford.cpp 125 | - euler-directed-graph.cpp 126 | - min-cost-flow.cpp 127 | - 4-cycle.cpp 128 | - 3-cycle.cpp 129 | - chromatic-number.cpp 130 | - geometry: 131 | - point-2d.cpp 132 | - convex-hull.cpp 133 | - lattice-point.cpp 134 | - nearest-2-points.cpp 135 | - order-by-angle.cpp 136 | - order-by-slope.cpp 137 | - point-inside-polygon.cpp 138 | - polygon-area.cpp 139 | - segment.cpp 140 | - halfplane.cpp 141 | - halfplane-intersection.cpp 142 | 143 | - dynamic-programming: 144 | - lis.cpp 145 | - knuth.cpp 146 | - egg-drop.cpp 147 | - d&c.cpp 148 | - convex-hull-trick.cpp 149 | - line-container.cpp 150 | - li-chao-tree.cpp 151 | - li-chao-segment.cpp 152 | - combinatorial: 153 | - weighted-matroid-intersection.cpp 154 | - simulated-annealing.cpp 155 | 156 | -------------------------------------------------------------------------------- /content/combinatorial/weighted-matroid-intersection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Maximum weight base in matroid intersection $O (r^(2n("O1"+"O2"))) $, where $r$ is the rank of the basis, and 3 | $n$ is the size of the ground set, O1 is the cost of Oracle query in the first matroid, and O2 the cost of Oracle query in second matroid. 4 | 5 | *Status:* Not tested 6 | */ 7 | template< 8 | typename W_t, // weight type 9 | typename T, // element of the ground set type 10 | typename Orc1, // Oracle of the first matroid 11 | typename Orc2 // Oracle of the second matroid 12 | > 13 | vector> weighted_matroid_intersection(const vector & ground_set, const Orc1 & matroid1, const Orc2 & matroid2){ 14 | int n = ground_set.size(); 15 | vector> res; 16 | vector in_set(n), in_matroid1(n), in_matroid2(n); 17 | vector> dist(n); 18 | vector> edges; 19 | vector par(n), l, r; 20 | l.reserve(n); 21 | r.reserve(n); 22 | while (1) { 23 | res.push_back({}); 24 | for (int i = 0; i < n; i++) 25 | if (in_set[i]) 26 | res.back().push_back(ground_set[i]); 27 | Orc1 m1 = matroid1; 28 | Orc2 m2 = matroid2; 29 | l.clear(); 30 | r.clear(); 31 | for (int i = 0; i < n; i++) 32 | if (in_set[i]) { 33 | m1.add(ground_set[i]); 34 | m2.add(ground_set[i]); 35 | l.push_back(i); 36 | } else { 37 | r.push_back(i); 38 | } 39 | fill(in_matroid1.begin(), in_matroid1.end(), 0); 40 | fill(in_matroid2.begin(), in_matroid2.end(), 0); 41 | for (int i : r) { 42 | in_matroid1[i] = m1.independed_with(ground_set[i]); 43 | in_matroid2[i] = m2.independed_with(ground_set[i]); 44 | } 45 | edges.clear(); 46 | for (int i : l) { 47 | { 48 | Orc1 m = matroid1; 49 | for (int j : l) 50 | if (i != j) 51 | m.add(ground_set[j]); 52 | 53 | for (int j : r) 54 | if (m.independed_with(ground_set[j])) 55 | edges.emplace_back(i, j); 56 | } 57 | { 58 | Orc2 m = matroid2; 59 | for (int j : l) 60 | if (i != j) 61 | m.add(ground_set[j]); 62 | 63 | for (int j : r) 64 | if (m.independed_with(ground_set[j])) 65 | edges.emplace_back(j, i); 66 | } 67 | } 68 | static constexpr W_t INF = numeric_limits::max(); 69 | fill(dist.begin(), dist.end(), pair{INF, -1}); 70 | fill(par.begin(), par.end(), -1); 71 | for (int i : r) 72 | if (in_matroid1[i]) 73 | dist[i] = {-ground_set[i].weight, 0}; 74 | 75 | while (1) { 76 | bool any = false; 77 | for (auto &[v, u] : edges) { 78 | if (dist[v].first == INF) 79 | continue; 80 | 81 | int coeff = in_set[v] ? -1 : 1; 82 | if (dist[u] > pair{dist[v].first + coeff * ground_set[u].weight, dist[v].second + 1}) { 83 | par[u] = v; 84 | dist[u] = {dist[v].first + coeff * ground_set[u].weight, dist[v].second + 1}; 85 | any = 1; 86 | } 87 | } 88 | if (!any) 89 | break; 90 | } 91 | int finish = -1; 92 | for (int v : r) 93 | if (in_matroid2[v] && dist[v].first != INF && (finish == -1 || dist[finish] > dist[v])) 94 | finish = v; 95 | if (finish == -1) 96 | break; 97 | 98 | for (; finish != -1; finish = par[finish]) 99 | in_set[finish] ^= 1; 100 | } 101 | return res; 102 | } -------------------------------------------------------------------------------- /content/data-structures/implicit-treap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | *Description:* Acts like an array, allowing us to reverse, sum, remove, slice, order of, and remove in $O(log n)$ 3 | *Status:* Tested 4 | */ 5 | #include 6 | using namespace __gnu_pbds; 7 | struct implicit_treap { 8 | static mt19937_64 MT; 9 | struct node{ 10 | node *l = nullptr, *r = nullptr, *par = nullptr; 11 | ll sz = 1, p = MT(), v, sumv, lzsum = 0; 12 | bool lzflip = false; 13 | node(ll x=0) { sumv=v=x; } 14 | } *root = nullptr; 15 | gp_hash_table mp; // Mapping values to nodes for order_of 16 | implicit_treap(){root=nullptr;} 17 | implicit_treap(ll x){root=new node(x);} 18 | ll sz(node* T) { return T?T->sz:0; } 19 | ll sumv(node* T) { return T?T->sumv:0;}; 20 | void upd(node* T){ 21 | if (T->l) T->l->par = T; 22 | if (T->r) T->r->par = T; 23 | T->sumv=T->v+sumv(T->l)+sumv(T->r); 24 | T->sz=1+sz(T->l)+sz(T->r); 25 | } 26 | void push(node* T){ 27 | if(T->lzsum){ 28 | T->v+=T->lzsum; 29 | T->sumv+=T->sz*T->lzsum; 30 | if(T->l)T->l->lzsum+=T->lzsum; 31 | if(T->r)T->r->lzsum+=T->lzsum; 32 | T->lzsum=0; 33 | } 34 | if(T->lzflip){ 35 | swap(T->l,T->r); 36 | if(T->l)T->l->lzflip^=1; 37 | if(T->r)T->r->lzflip^=1; 38 | T->lzflip=0; 39 | } 40 | } 41 | void merge(node*& T,node* L,node* R){ 42 | if(!L||!R){T=L?L:R;return;} 43 | push(L);push(R); 44 | if(L->p>R->p) merge(L->r,L->r,R), T=L; 45 | else merge(R->l,L,R->l), T=R; 46 | upd(T); 47 | } 48 | void split(node* T,int k,node*& L,node*& R){ 49 | if(!T){L=R=nullptr;return;} 50 | push(T); 51 | int key=sz(T->l); 52 | if(key<=k) split(T->r,k-key-1,T->r,R), L=T; 53 | else split(T->l,k,L,T->l), R=T; 54 | upd(T); 55 | } 56 | void set(node* T,int k,ll x){ 57 | push(T); 58 | int key=sz(T->l); 59 | if(key==k)T->v=x; 60 | else if(kl,k,x); 61 | else set(T->r,k-key-1,x); 62 | upd(T); 63 | } 64 | node* find(node* T,int k){ 65 | push(T); 66 | int key=sz(T->l); 67 | if(key==k) return T; 68 | if(kl,k); 69 | return find(T->r,k-key-1); 70 | } 71 | int size(){return sz(root);} 72 | implicit_treap& merge(implicit_treap& O){ 73 | merge(root,root,O.root); 74 | return *this; 75 | } 76 | implicit_treap split(int k){ 77 | implicit_treap ans; 78 | split(root,k,root,ans.root); 79 | return ans; 80 | } 81 | void erase(int i,int j){ 82 | node *T1,*T2,*T3; 83 | split(root,i-1,T1,T2), split(T2,j-i,T2,T3); 84 | merge(root,T1,T3); 85 | } 86 | void erase(int k){erase(k,k);} 87 | void set(int k,ll x){set(root,k,x);} 88 | ll operator[](int k){return find(root,k)->v;} 89 | ll query(int i,int j){ 90 | node *T1,*T2,*T3; 91 | split(root,i-1,T1,T2), split(T2,j-i,T2,T3); 92 | ll ans=sumv(T2); 93 | merge(T2,T2,T3), merge(root,T1,T2); 94 | return ans; 95 | } 96 | void update(int i,int j,ll x){ 97 | node *T1,*T2,*T3; 98 | split(root,i-1,T1,T2), split(T2,j-i,T2,T3); 99 | T2->lzsum+=x; 100 | merge(T2,T2,T3), merge(root,T1,T2); 101 | } 102 | void flip(int i,int j){ 103 | node *T1,*T2,*T3; 104 | split(root,i-1,T1,T2), split(T2,j-i,T2,T3); 105 | T2->lzflip^=1; 106 | merge(T2,T2,T3), merge(root,T1,T2); 107 | } 108 | void insert(int i,ll x){ 109 | node *T1,*T2; 110 | split(root,i-1,T1,T2); 111 | merge(T1,T1,new node(x)), merge(root,T1,T2); 112 | } 113 | void push_back(ll x){auto nn = new node(x); merge(root,root, nn); mp[x] = nn;} 114 | int order_of(int x) { 115 | node* t = mp[x]; 116 | vector path; 117 | for (node* cur = t; cur; cur = cur->par) 118 | path.push_back(cur); 119 | reverse(path.begin(), path.end()); 120 | for (node* n : path) push(n), upd(n); 121 | int idx = sz(t->l); 122 | node* cur = t; 123 | while (cur->par) { 124 | if (cur == cur->par->r) 125 | idx += sz(cur->par->l) + 1; 126 | cur = cur->par; 127 | } 128 | return idx; 129 | } 130 | }; 131 | mt19937_64 implicit_treap::MT(chrono::system_clock::now().time_since_epoch().count()); 132 | -------------------------------------------------------------------------------- /content.typ: -------------------------------------------------------------------------------- 1 | #import "lib/hash.typ": md5, hex 2 | 3 | #set page( 4 | paper: "a4", 5 | columns: 2, 6 | margin: (x: 2em, y: 2em), 7 | numbering: "1/1" 8 | ) 9 | 10 | #set text( 11 | font: "New Computer Modern", 12 | size: 7pt 13 | ) 14 | 15 | #let title-case(string) = { 16 | if string.len() <= 3 { 17 | return upper(string) 18 | } 19 | 20 | return string.replace( 21 | regex("[A-Za-z]+('[A-Za-z]+)?"), 22 | word => upper(word.text.first()) + lower(word.text.slice(1)) 23 | ) 24 | } 25 | 26 | #let content-to-string(content) = { 27 | if content.has("text") { 28 | content.text 29 | } else if content.has("children") { 30 | content.children.map(content-to-string).join("") 31 | } else if content.has("body") { 32 | content-to-string(content.body) 33 | } else if content == [ ] { 34 | " " 35 | } 36 | } 37 | 38 | #let get-code-hash(string) = { 39 | string = string.replace(regex("[\n\t\s]"), "") 40 | hex(md5(string)).slice(0, 6) 41 | } 42 | 43 | #let comments-regex = regex("\/\*[\s\S]*?\*\/") 44 | 45 | #let get-description-from-code(string) = { 46 | let comments = string.find(comments-regex) 47 | 48 | if type(comments) != str or string.trim().at(0) != "/" { 49 | return text(red)[*You must provide a description for each template code!*] 50 | } 51 | 52 | let lines = comments.split("\n") 53 | lines.slice(1, lines.len() - 1).join("\\").trim() 54 | } 55 | 56 | #let remove-description-from-code(string) = { 57 | if string.trim().at(0) != "/" { 58 | return string 59 | } 60 | string.replace(comments-regex, "", count: 1).trim() 61 | } 62 | 63 | #let template-code(title: [], only-code: [], body) = { 64 | let code-lines = only-code.split("\n").len() 65 | let text-size = if code-lines > 90 { 5.3pt } else { 7pt } 66 | 67 | block( 68 | breakable: false, 69 | radius: 5pt, 70 | inset: 1em, 71 | stroke: 0.9pt, 72 | spacing: 1.5em, 73 | width: 100% 74 | )[ 75 | #place(dy: -15pt, dx: 220pt)[ 76 | #block( 77 | fill: black, 78 | inset: 3pt, 79 | )[ 80 | #text(fill: green)[\#] 81 | #text(fill: white, weight: "semibold")[ 82 | #get-code-hash(only-code) 83 | ] 84 | ] 85 | ] 86 | 87 | #place(dy: -15pt)[ 88 | #block( 89 | fill: black, 90 | inset: 3pt 91 | )[ 92 | #text(fill: white, weight: "semibold")[ 93 | #title 94 | ] 95 | ] 96 | ] 97 | 98 | #set text(size: text-size) 99 | #body 100 | ] 101 | } 102 | 103 | #let template-section-title(title) = { 104 | text(weight: "black", size: 15pt)[#title] 105 | } 106 | 107 | #let typst-section(title: [], content: []) = { 108 | block( 109 | breakable: false, 110 | inset: 1em, 111 | stroke: 0.9pt, 112 | spacing: 2em, 113 | width: 100% 114 | )[ 115 | #align(center)[#text(size: 10pt, weight: "bold")[#title]] 116 | #eval(content, mode: "markup") 117 | ] 118 | } 119 | 120 | #for x in yaml("tracker.yaml") { 121 | let content-list = x.at(1) 122 | for i in range(0, content-list.len()) { 123 | for (folder-name, files) in content-list.at(i) { 124 | let title-section = title-case(folder-name.split("-").join(" ")) 125 | template-section-title(title-section) 126 | 127 | for file-name in files { 128 | let path = "content/" + folder-name + "/" + file-name 129 | let file-extension = path.split(".").at(-1) 130 | let template-title = title-case(file-name.split(".").at(0).split("-").join(" ")) 131 | let file = read(path) 132 | 133 | if file-extension == "typ" { 134 | typst-section(title: template-title, content: file) 135 | } else if file-extension == "cpp" { 136 | let all-code = raw(file, lang: "cpp") 137 | let comments = get-description-from-code(content-to-string(all-code)) 138 | let without-comments = remove-description-from-code(content-to-string(all-code)) 139 | 140 | template-code(title: template-title, only-code: without-comments)[ 141 | #eval(comments, mode: "markup") 142 | #line(length: 100%) 143 | #raw(without-comments, lang: "cpp") 144 | ] 145 | } 146 | } 147 | } 148 | if i != content-list.len() - 1 { 149 | pagebreak() 150 | } 151 | } 152 | } 153 | --------------------------------------------------------------------------------