0% found this document useful (0 votes)
4 views

Notebook - template for icpc

The document is a table of contents for a programming notebook, detailing various algorithms and data structures. It includes sections on flows, C++, strings, graph algorithms, and math, with specific algorithms listed under each category. Each section is numbered and includes subtopics, indicating a comprehensive guide for competitive programming techniques.

Uploaded by

nbaro2401
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

Notebook - template for icpc

The document is a table of contents for a programming notebook, detailing various algorithms and data structures. It includes sections on flows, C++, strings, graph algorithms, and math, with specific algorithms listed under each category. Each section is numbered and includes subtopics, indicating a comprehensive guide for competitive programming techniques.

Uploaded by

nbaro2401
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 51

4 Flows 14

Fast and Fourier ICPC Team Notebook 4.1 Edmons-Karp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14


4.2 Dinic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Contents 4.3 Push-Relabel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4.4 Konig . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1 C++ 2 4.5 MCBM Augmenting Algorithm . . . . . . . . . . . . . . . . . . . . . 17
1.1 C++ template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
4.6 Hungarian Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.2 Opcion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.7 Min-Cost Max-Flow Algorithm . . . . . . . . . . . . . . . . . . . . . 18
1.3 Bits Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.8 Min-Cost Max-Flow Algorithm 2 . . . . . . . . . . . . . . . . . . . . 18
1.4 Random . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
4.9 Blossom . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.5 Custom Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.6 Other . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 5 Data Structures 20
5.1 Disjoint Set Union . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2 Strings 4 5.2 SQRT Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.1 Z’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
5.3 Fenwick Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.2 KMP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 5.4 Fenwick Tree 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.4 Manacher Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.5 Segment Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.5 Minimum Expression . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.6 ST Lazy Propagation . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.6 Trie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.7 Persistent ST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7 Suffix Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.8 Segtree 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
2.8 Aho-Corasick . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 5.9 Segtree iterativo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
5.10 RMQ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1

2.9 Suffix Automaton . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6


2.10 Palindromic Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 5.11 Sack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.11 Suffix Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 5.12 Heavy Light Decomposition . . . . . . . . . . . . . . . . . . . . . . . 23
5.13 Treap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3 Graph algorithms 8 5.14 Implicit Treap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.1 Articulation Points and Bridges . . . . . . . . . . . . . . . . . . . . . 8 5.15 Implicit Treap Father . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.2 Biconnected Components . . . . . . . . . . . . . . . . . . . . . . . . 9 5.16 Ordered Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.3 Topological Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 5.17 Mo’s Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.4 Kosaraju: Strongly connected components . . . . . . . . . . . . . . . 10 5.18 Dynamic Connectivity . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.5 Tarjan: Strongly connected components . . . . . . . . . . . . . . . . 10 5.19 Link Cut Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.6 MST Kruskal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.7 MST Prim . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6 Math 27
3.8 Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 6.1 Sieve of Eratosthenes . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.9 Bellman-Ford . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6.2 Count primes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.10 Shortest Path Faster Algorithm . . . . . . . . . . . . . . . . . . . . . 11 6.3 Segmented Sieve . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.11 Floyd-Warshall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6.4 Polynomial Multiplication . . . . . . . . . . . . . . . . . . . . . . . . 28
3.12 LCA Binary Lifting . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 6.5 Fast Fourier Transform . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.13 2 SAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 6.6 FHT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.14 2 SAT Kosaraju y Tarjan . . . . . . . . . . . . . . . . . . . . . . . . 12 6.7 Fibonacci Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.15 Centroid Decomposition . . . . . . . . . . . . . . . . . . . . . . . . . 13 6.8 Matrix Exponentiation . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.16 Tree Binarization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 6.9 Binary Exponentiation . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.17 Eulerian Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 6.10 Euler’s Totient Function . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.11 Extended Euclidean (Diophantic) . . . . . . . . . . . . . . . . . . . . 30 DP Optimization Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.12 Inversa modular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Combinatorics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
6.13 Legendre’s Formula . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Number Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
6.14 Mobious . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 String Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.15 Miller Rabin Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Graph Theory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
6.16 Pollard Rho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Games . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.17 Chinese Remainder Theorem . . . . . . . . . . . . . . . . . . . . . . 32 Bit tricks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6.18 Simplex . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Math . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
6.19 Gauss Jordan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.20 Gauss Jordan Modular . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.21 Berlekamp Massey . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 1 C++
6.22 Lagrange Interpolation . . . . . . . . . . . . . . . . . . . . . . . . . . 34
6.23 Discrete Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 1.1 C++ template
6.24 Fractions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.25 Modular Int . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 #include <bits/stdc++.h>
7 Dynamic Programming 35 #define fi first
7.1 Edit Distance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 #define se second
#define forn(i,n) for(int i=0; i< (int)n; ++i)
7.2 Longest common subsequence . . . . . . . . . . . . . . . . . . . . . . 36 #define for1(i,n) for(int i=1; i<= (int)n; ++i)
7.3 Longest increasing subsequence . . . . . . . . . . . . . . . . . . . . . 36 #define fore(i,l,r) for(int i=(int)l; i<= (int)r; ++i)
7.4 Trick to merge intervals . . . . . . . . . . . . . . . . . . . . . . . . . 36 #define ford(i,n) for(int i=(int)(n) - 1; i>= 0; --i)
#define fored(i,l,r) for(int i=(int)r; i>= (int)l; --i)
7.5 Trick Sets DP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
2

#define pb push_back
7.6 Divide and Conquer . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 #define el ’\n’
7.7 Knuth’s Optimization . . . . . . . . . . . . . . . . . . . . . . . . . . 37 #define d(x) cout<< #x<< " " << x<<el
7.8 Convex Hull Trick . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 #define ri(n) scanf("%d",&n)
#define sz(v) int(v.size())
7.9 CH Trick Dynamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 #define all(v) v.begin(),v.end()
8 Geometry 38 using namespace std;
8.1 Point . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 typedef long long ll;
8.2 Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 typedef double ld;
8.3 Convex Hull . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 typedef pair<int,int> ii;
typedef pair<ll,ll> pll;
8.4 Polygon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 typedef tuple<int, int, int> iii;
8.5 Circle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 typedef vector<int> vi;
8.6 Radial Order . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 typedef vector<ii> vii;
typedef vector<ll> vll;
8.7 Halfplane . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 typedef vector<ld> vd;
8.8 KD Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
8.9 Minkowski Sum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 const int inf = 1e9;
const int nax = 1e5+200;
9 Miscellaneous 44 const ld pi = acos(-1);
9.1 Counting Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 const ld eps= 1e-9;
9.2 Expression Parsing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 int dr[] = {1,-1,0, 0,1,-1,-1, 1};

1
9.3 Ternary Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 int dc[] = {0, 0,1,-1,1, 1,-1,-1};

C++
ostream& operator<<(ostream& os, const ii& pa) { //
10 Theory 46 DEBUGGING
1.2
return os << "("<< pa.fi << ", " << pa.se << ")";
}
1.4 Random

Opcion
int main(){
ios_base::sync_with_stdio(false); // Declare random number generator
cin.tie(NULL); cout.tie(NULL); mt19937_64 rng(0); // 64 bit, seed = 0
cout << setprecision(20)<< fixed; mt19937 rng(chrono::steady_clock::now().time_since_epoch
} ().count()); // 32 bit
// Use it to shuffle a vector
shuffle(all(vec), rng);
1.2 Opcion
// Create int/real uniform dist. of type T in range [l, r
// En caso de que no sirva #include <bits/stdc++.h> ]
#include <algorithm> uniform_int_distribution<T> / uniform_real_distribution<T
#include <iostream> > dis(l, r);
#include <iterator> dis(rng); // generate a random number in [l, r]
#include <sstream> int rd(int l, int r) { return uniform_int_distribution<
#include <fstream> int>(l, r)(rng);}
#include <cassert>
#include <climits>
#include <cstdlib>
#include <cstring> 1.5 Custom Hash
#include <string>
#include <cstdio> struct custom_hash {
#include <vector> static ll splitmix64(ll x) {
#include <cmath> // http://xorshift.di.unimi.it/splitmix64.c
#include <queue> x += 0x9e3779b97f4a7c15;
3

#include <deque> x = (x ˆ (x >> 30)) * 0xbf58476d1ce4e5b9;


#include <stack> x = (x ˆ (x >> 27)) * 0x94d049bb133111eb;
#include <list> return x ˆ (x >> 31);
#include <map> }
#include <set>
#include <bitset> size_t operator()(ll x) const {
#include <iomanip> static const ll FIXED_RANDOM = chrono::
#include <unordered_map> steady_clock::now().time_since_epoch().count()
;
//// return splitmix64(x + FIXED_RANDOM);
#include <tuple> }
#include <random> };
#include <chrono> unordered_map<ll,int, custom_hash> mapa;

1.3 Bits Manipulation 1.6 Other

mask |= (1<<n) // PRENDER BIT-N #pragma GCC optimize("O3")


//(UNCOMMENT WHEN HAVING LOTS OF RECURSIONS)\
mask ˆ= (1<<n) // FLIPPEAR BIT-N #pragma comment(linker, "/stack:200000000")
mask &= ˜(1<<n) // APAGAR BIT-N //(UNCOMMENT WHEN NEEDED)
if(mask&(1<<n)) // CHECKEAR BIT-N #pragma GCC optimize("Ofast,unroll-loops,no-stack-
T = mask&(-mask); // LSO protector,fast-math")
__builtin_ffs(mask); // INDICE DEL LSO #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,

1
// iterar sobre los subconjuntos del conjunto S mmx,avx,tune=native")
for(int subset= S; subset; subset= (subset-1) & S)

C++
for (int subset=0;subset=subset-S&S;) // Increasing // Custom comparator for set/map
order struct comp {
bool operator()(const double& a, const double& b) vi get_phi(string &s) { // O(|s|)
const { int j = 0, n = sz(s); vi pi(n);
return a+EPS<b;} for1(i,n-1){
}; while (j > 0 && s[i] != s[j]) j = pi[j-1];
set<double,comp> w; // or map<double,int,comp> j += (s[i] == s[j]);
// double inf pi[i] = j;
const double DINF=numeric_limits<double>::infinity(); }
return pi;
int main() { }
// Ouput a specific number of digits past the decimal void kmp(string &t, string &p){ // O(|t| + |p|)
point, vi phi = get_phi(p);
// in this case 5 int matches = 0;
// #include <iomanip> for(int i = 0, j = 0; i < sz(t); ++i ) {
cout << setfill(’ ’) << setw(3) << 2 << endl; while(j > 0 && t[i] != p[j] ) j = phi[j-1];
if(t[i] == p[j]) ++j;
cout.setf(ios::fixed); cout << setprecision(5); if(j == sz(p)) {
cout << 100.0/7.0 << endl; matches++;
cout.unsetf(ios::fixed j = phi[j-1];
// Output the decimal point and trailing zeros }
cout.setf(ios::showpoint); cout << 100.0 << endl; cout. }
unsetf(ios::showpoint); }
/// Automaton
// Output a + before positive values /// Complexity O(n*C) where C is the size of the alphabet
cout.setf(ios::showpos); cout << 100 << " " << -100 << int aut[nax][26];
endl; cout.unsetf(ios::showpos); void kmp_aut(string &p) {
int n = sz(p);
// Output numerical values in hexadecimal vi phi = get_phi(p);
4

cout << hex << 100 << " " << 1000 << " " << 10000 << forn(i, n+1) {
dec << endl; forn(c, 26) {
} if (i==n || (i>0 && ’a’+c!= p[i])) aut[i][c] = aut[
phi[i-1]][c];
else aut[i][c] = i + (’a’+c == p[i]);
}
2 Strings }
}
2.1 Z’s Algorithm /// Automaton
int wh[nax+2][MAXC]; //wh[i][j] = a donde vuelvo si
// O(|s|) estoy en i y pongo una j
void build(string &s){
vi z_function(string &s){ int lps=0;
int n = s.size(); wh[0][s[0]-’a’] = 1;
vi z(n); fore(i,1,sz(s)){
int x = 0, y = 0; fore(j,0,MAXC-1) wh[i][j]=wh[lps][j];
for(int i = 1; i < n; ++i) { if(i<sz(s)){
z[i] = max(0, min(z[i-x], y-i+1)); wh[i][s[i]-’a’] = i+1;
while (i+z[i] < n && s[z[i]] == s[i+z[i]]) lps = wh[lps][s[i]-’a’];
x = i, y = i+z[i], z[i]++; }
} }

2
return z; }
}

STRINGS
2.2 KMP 2.3 Hashing
2.4
/// 1000234999, 1000567999, 1000111997, 1000777121, }
999727999, 1070777777
const int MOD[] = { 1001864327, 1001265673 }, N = 3e5;

Manacher Algorithm
const ii BASE(257, 367), ZERO(0, 0), ONE(1, 1); 2.5 Minimum Expression
inline int add(int a, int b, int mod) { return a+b >= mod
? a+b-mod : a+b; }
inline int sbt(int a, int b, int mod) { return a-b < 0 ? int minExp(string &t) {
a-b+mod : a-b; } int i = 0, j = 1, k = 0, n = sz(t), x, y;
inline int mul(int a, int b, int mod) { return ll(a) * b while (i < n && j < n && k < n) {
% mod;} x = i+k;
inline ll operator ! (const ii a) { return (ll(a.fi) << y = j+k;
32) | a.se; } if (x >= n) x -= n;
inline ii operator + (const ii& a, const ii& b) { if (y >= n) y -= n;
return {add(a.fi, b.fi, MOD[0]), add(a.se, b.se, MOD if (t[x] == t[y]) ++k;
[1])};} else if (t[x] > t[y]) {
inline ii operator - (const ii& a, const ii& b) { i = j+1 > i+k+1 ? j+1 : i+k+1;
return {sbt(a.fi, b.fi, MOD[0]), sbt(a.se, b.se, MOD swap(i, j);
[1])};} k = 0;
inline ii operator * (const ii& a, const ii& b) { } else {
return {mul(a.fi, b.fi, MOD[0]), mul(a.se, b.se, MOD j = i+1 > j+k+1 ? i+1 : j+k+1;
[1])};} k = 0;
}
ii base[N]{ONE}; }
void prepare() { for1(i, N-1) base[i] = base[i-1] * BASE; return i;
} }
template <class type>
struct hashing { /// HACELEEE PREPAREEEE!!!
vii ha; // ha[i] = t[i]*p0 + t[i+1]*p1 + t[i+2]* 2.6 Trie
5

p2 + ..
hashing(type &t): ha(sz(t)+1, ZERO){ const static int N = 2e6, alpha = 26, B = 30; // MAX:
for(int i = sz(t) - 1; i >= 0; --i) ha[i] = ha[i+1] * abecedario, bits
BASE + ii{t[i], t[i]}; int to[N][alpha], cnt[N], sz;
} inline int conv(char ch){ return ch - ’a’; } // CAMBIAR
ii query(int l, int r){ return ha[l] - ha[r+1] * base[r string to_bin(int num, int bits){ // B: Max(bits), bits
-l+1]; } //[l,r] : size
}; return bitset<B>(num).to_string().substr(B - bits);}
// AGREGAR LO QUE HAYA QUE RESETEAR !!!!
void init(){
2.4 Manacher Algorithm forn(i, sz+1) cnt[i] = 0, memset(to[i], 0, sizeof to[i
]);
sz = 0;
// f = 1 para pares, 0 impar }
//a a a a a a void add(const string &s){
//1 2 3 3 2 1 f = 0 impar int u = 0;
//0 1 2 3 2 1 f = 1 par for(char ch: s){
void manacher(string &s, int f, vi &d){ int c = conv(ch);
int l=0, r=-1, n=sz(s); if(!to[u][c]) to[u][c] = ++sz;
d.assign(n,0); u = to[u][c];
forn(i, n){ }

2
int k=(i>r? (1-f) : min(d[l+r-i+ f], r-i+f)) + f; cnt[u]++;
}

STRINGS
while(i+k-f<n && i-k>=0 && s[i+k-f]==s[i-k]) ++k;
d[i] = k - f; --k;
if(i+k-f > r) l=i-k, r=i+k-f;
} 2.7 Suffix Array
// forn(i,n) d[i] = (d[i]-1+f)*2 + 1-f;
2.8
struct SuffixArray { // test line 11 for(string& s: str) add(s);
vi sa, lcp; build();
SuffixArray(string& s, int lim=256){ }

Aho-Corasick
int n = sz(s) + 1, k = 0, a, b; void add(string &s) {
s.pb(’$’); int v = 0;
vi x(all(s)), y(n), ws(max(n, lim)), rank for(char ch : s) {
(n); int c = conv(ch);
sa = lcp = y, iota(all(sa), 0); if(!to[v][c]) to[v][c] = ++sz;
for (int j = 0, p = 0; p < n; j = max(1, v = to[v][c];
j * 2), lim = p) { }
p = j; ++cnt_w[v];
// iota(all(y), n - j); end_w[v] = ++words;
// forn(i,n) if (sa[i] >= j) y[p++] }
= sa[i] - j; void build() {
forn(i,n) y[i] = (sa[i] - j >= 0 queue<int> q{{0}};
? 0 : n) + sa[i]-j; // this while(sz(q)) {
replace the two lines int u = q.front(); q.pop();
// before hopefully xd forn(i, alpha) {
fill(all(ws), 0); int v = to[u][i];
forn(i,n) ws[x[i]]++; if(!v) to[u][i] = to[ fail[u] ][i];
for1(i,lim-1) ws[i] += ws[i - 1]; else q.push(v);
for (int i = n; i--;) sa[--ws[x[y if(!u || !v) continue;
[i]]]] = y[i]; fail[v] = to[ fail[u] ][i];
swap(x, y), p = 1, x[sa[0]] = 0; fail_out[v] = end_w[ fail[v] ] ? fail[v] :
for1(i,n-1) a = sa[i - 1], b = sa fail_out[ fail[v] ];
[i], x[b] = cnt_w[v] += cnt_w[ fail[v] ];
(y[a] == y[b] && y[a + j] }
6

== y[b + j]) ? p - 1 }
: p++; }
} int match(string &s){
for1(i,n-1) rank[sa[i]] = i; int v = 0, mat = 0;
for (int i = 0, j; i < n - 1; lcp[rank[i for(char ch: s) {
++]] = k) // lcp(i): lcp suffix i-1,i v = to[v][conv(ch)];
for (k && k--, j = sa[rank[i] - mat += cnt_w[v];
1]; }
s[i + k] == s[j + return mat;
k]; k++); }
} };
};

2.9 Suffix Automaton


2.8 Aho-Corasick
struct node {
const static int N = 1e5+1, alpha = 26; int len, link;
int sz, to[N][alpha], fail[N], end_w[N], cnt_w[N], map<char, int> to; // if TLE --> change to array<int,
fail_out[N]; 27> to;
inline int conv(char ch) { return ch-’a’; } bool terminal;
struct aho_corasick{ };

2
int words=0; const int N = 4e5+1; // el doble del MAXN

STRINGS
aho_corasick(vector<string>& str){ node st[N];
forn(i, sz+1) fail[i] = end_w[i] = cnt_w[i] = int sz, last, occ[N], cnt[N];
fail_out[i] = 0; bool seen[N];
forn(i, sz+1) memset(to[i], 0, sizeof to[i]);
sz = 0; struct suf_aut{
2.10
suf_aut(string& s){ forn(i, sz(t)){
forn(i, sz) st[i] = node(); while(v && !st[v].to.count(t[i])) v = st[v].link, l
sz = 1; = st[v].len;

Palindromic Tree
st[0].len = st[0].terminal = last = 0; if(st[v].to.count(t[i])) v = st[v].to[t[i]], ++l;
st[0].link = -1; if(i >= n){
for(char c: s) extend(c); if(v && st[st[v].link].len >= n) v = st[v].link,
} l = st[v].len;
void extend(char c) { if(!seen[v] && l >= n) seen[v] = 1, ans += cnt[v
int v = sz++, p = last; ]; // Match
st[v].len = st[p].len + 1; }
while(p != -1 && !st[p].to[c]) st[p].to[c] = v, p = }
st[p].link; return ans;
if(p == -1) st[v].link = 0; }
else{ };
int q = st[p].to[c];
if(st[p].len + 1 == st[q].len) st[v].link = q;
else{ 2.10 Palindromic Tree
int w = sz++;
st[w].len = st[p].len + 1;
st[w].to = st[q].to; struct palindromic_tree{
st[w].link = st[q].link; static const int SIGMA = 26;
while(p != -1 && st[p].to[c] == q) st[p].to[c] = struct node{
w, p = st[p].link; int link, len, p, to[SIGMA];
st[q].link = st[v].link = w; node(int len, int link=0,int p=0):
} len(len),link(link),p(p){
} memset(to,0,sizeof(to));
cnt[last = v] = 1; }
} };
7

int dfs_occ(int v){ int last;


if(occ[v]) return occ[v]; vector<node> st;
occ[v] = st[v].terminal; palindromic_tree():last(0){fore(i,-1,0)st.pb(node(i));}
for(auto &[_, u] : st[v].to) occ[v] += dfs_occ(u);
return occ[v]; void add(int i, const string &s){
} int c = s[i]-’a’;
void calc_cnt(){ int p = last;
vi ord(sz - 1); iota(all(ord), 1); while(s[i-st[p].len-1]!=s[i]) p=st[p].link;
sort(all(ord), [&](int i, int j){ return st[i].len > if(st[p].to[c]){
st[j].len; }); last = st[p].to[c];
for(int v: ord) cnt[st[v].link] += cnt[v]; // Add }else{
cnt to link int q=st[p].link;
} while(s[i-st[q].len-1]!=s[i]) q=st[q].link;
string LCS(string &t){ q=max(1,st[q].to[c]);
int v = 0, l = 0; last = st[p].to[c] = sz(st);
ii mx{0, -1}; st.pb(node(st[p].len+2,q,p));
forn(i, sz(t)){ }
while(v && !st[v].to.count(t[i])) v = st[v].link, l }
= st[v].len; };
if(st[v].to.count(t[i])) v = st[v].to[t[i]], ++l;
mx = max(mx, {l, i}); // LCS ending at position i

2
}
return t.substr(mx.se - mx.fi + 1, mx.fi); 2.11 Suffix Tree

STRINGS
}
int cyclic_match(string& t){ const int N=1000000, // maximum possible number of
int n = sz(t), v = 0, l = 0, ans = 0; nodes in suffix tree
t += t; INF=1000000000; // infinity constant
string a; // input string for which the suffix tree letter to suffix
is being built tp=r[tv]-(tp-r[ts-2])+2;goto suff;
int t[N][26], // array of transitions (state, letter) }
l[N], // left... }
r[N], // ...and right boundaries of the substring
of a which correspond to incoming edge void build() {
p[N], // parent of the node ts=2;
tv=0;
s[N], // suffix link tp=0;
tv, // the node of the current suffix (if we’re fill(r,r+N,(int)a.size()-1);
mid-edge, the lower node of the edge) // initialize data for the root of the tree
tp, // position in the string which corresponds s[0]=1;
to the position on the edge (between l[tv] and r[ l[0]=-1;
tv], inclusive) r[0]=-1;
ts, // the number of nodes l[1]=-1;
la; // the current character in the string r[1]=-1;
void ukkadd(int c) { // add character s to the tree memset (t, -1, sizeof t);
suff:; // we’ll return here after each fill(t[1],t[1]+26,0);
transition to the suffix (and will add character // add the text to the tree, letter by letter
again) for (la=0; la<(int)a.size(); ++la)
if (r[tv]<tp) { // check whether we’re still within ukkadd (a[la]-’a’);
the boundaries of the current edge }
// if we’re not, find the next edge. If it doesn’
t exist, create a leaf and add it to the tree
if (t[tv][c]==-1) {t[tv][c]=ts;l[ts]=la;p[ts++]=
tv;tv=s[tv];tp=r[tv]+1;goto suff;}
3 Graph algorithms
tv=t[tv][c];tp=l[tv];
} // otherwise just proceed to the next edge 3.1 Articulation Points and Bridges
8

if (tp==-1 || c==a[tp]-’a’)
tp++; // if the letter on the edge equal c, go // Complexity: V + E
down that edge // Given an undirected graph
else { int n, timer, tin[nax], low[nax];
// otherwise split the edge in two with middle in vi g[nax]; // adjacency list of graph
node ts
l[ts]=l[tv];r[ts]=tp-1;p[ts]=p[tv];t[ts][a[tp]-’a void dfs(int u, int p) {
’]=tv; tin[u] = low[u] = ++timer;
// add leaf ts+1. It corresponds to transition int children=0;
through c. for (int v : g[u]) {
t[ts][c]=ts+1;l[ts+1]=la;p[ts+1]=ts; if (v == p) continue;
// update info for the current node - remember to if (tin[v]) low[u] = min(low[u], tin[v]);
mark ts as parent of tv else {
l[tv]=tp;p[tv]=ts;t[p[ts]][a[l[ts]]-’a’]=ts;ts dfs(v, u);

3
+=2; low[u] = min(low[u], low[v]);
// prepare for descent

GRAPH ALGORITHMS
if (low[v] > tin[u]) // BRIDGE
// tp will mark where are we in the current IS_BRIDGE(u, v);
suffix
tv=s[p[ts-2]];tp=l[ts-2]; if (low[v] >= tin[u] && p!=-1) // POINT
// while the current suffix is not over, descend IS_CUTPOINT(u);
while (tp<=r[ts-2]) {tv=t[tv][a[tp]-’a’];tp+=r[tv ++children;
]-l[tv]+1;} }
// if we’re in a node, add a suffix link to it, }
otherwise add the link to ts if(p == -1 && children > 1) // POINT
// (we’ll create ts on next iteration). IS_CUTPOINT(u);
if (tp==r[ts-2]+1) s[ts-2]=tv; else s[ts-2]=ts; }
// add tp to the new edge and return to add void find_articulations() {
3.2
timer = 0; low[u] = min(low[u], low[v]);
forn(i,n) if(!tin[i]) dfs(i,-1); } else if (i != p && num[v] < num[u]) {
} st.push(i);

Biconnected Components
low[u] = min(low[u], num[v]);
}
3.2 Biconnected Components }
}
struct edge { void build_tree() {
int u, v, comp; //A que componente biconexa tree.clear(); id.resize(N); tree.reserve(2*N);
pertenece forn(u,N)
bool bridge; //Si la arista es un puente if (art[u]) id[u] = sz(tree); tree.pb({})
}; ;
for (auto &comp : comps) {
vector<int> g[nax]; //Lista de adyacencia sort(all(comp));
vector<edge> e; //Lista de aristas comp.resize(unique(all(comp)) - comp.begin());
stack<int> st; int node = sz(tree);
int low[nax], num[nax], cont; tree.pb({});
int art[nax]; //Si el nodo es un punto de articulacion for (int u : comp) {
//vector<vector<int>> comps; //Componentes biconexas if (art[u]) {
//vector<vector<int>> tree; //Block cut tree tree[id[u]].pb(node);
//vector<int> id; //Id del nodo en el block cut tree tree[node].pb(id[u]);
int nbc; //Cantidad de componentes biconexas }else id[u] = node;
int N, M; //Cantidad de nodos y aristas }
}
void add_edge(int u, int v){ }
g[u].pb(sz(e)); g[v].pb(sz(e)); void doit() {
e.pb({u, v, -1, false}); cont = nbc = 0;
9

} // comps.clear();
void dfs(int u, int p = -1) { forn(i,N) {
low[u] = num[u] = cont++; g[i].clear(); num[i] = -1; art[i] = 0;
for (int i : g[u]) { }
edge &ed = e[i]; forn(i,N){
int v = ed.uˆed.vˆu; if(num[i]<0) dfs(i), --art[i];
if(num[v]<0){ }
st.push(i); }
dfs(v, i);
if (low[v] > num[u]) ed.bridge =
true; //bridge
if (low[v] >= num[u]) { 3.3 Topological Sort
art[u]++; //articulation
int last; //start
biconnected vi g[nax], ts;

3
// comps.pb({}); bool seen[nax];

GRAPH ALGORITHMS
do { void dfs(int u){
last = st.top(); seen[u] = true;
st.pop(); for(int v: g[u])
e[last].comp = if (!seen[v])
nbc; dfs(v);
// comps.back().pb(e ts.pb(u);
[last].u); }
// comps.back().pb(e void topo(int n){
[last].v); forn(i,n) if (!seen[i]) dfs(i);
} while (last != i); reverse(all(ts));
nbc++; //end biconnected }
}
3.4
bool operator < (const edge &o) const{ return w < o.w;}
};
3.4 Kosaraju: Strongly connected components vector<edge> g;

Kosaraju: Strongly connected components


void kruskal(int n){
vi g[nax], gr[nax], ts; sort(all(g)); dsu uf(n); // union-find
bool seen[nax]; for(auto& [u, v, w]: g)
int scc[nax], comp; if(!uf.is_same_set(u, v)) uf.union_set(u, v);
void dfs1(int u){ }
seen[u] = 1;
for(int v: g[u]) if(!seen[v]) dfs1(v);
ts.pb(u); 3.7 MST Prim
}
void dfs2(int u){
scc[u] = comp; //Complexity O(E * log V)
for(int v : gr[u]) if(scc[v] == -1) dfs2(v); vector<ii> g[nax];
} bool seen[nax];
int find_scc(int n){ //TENER CREADO EL GRAFO REVERSADO gr priority_queue<ii> pq;
forn(i, n) if(!seen[i]) dfs1(i); void process(int u) {
reverse(all(ts)); seen[u] = true;
memset(scc, -1, sizeof scc); for (ii v: g[u])
for(int u: ts) if(scc[u] == -1) ++comp, dfs2(u); if (!seen[v.fi])
return comp; pq.push(ii(-v.se, v.fi));
} }
int prim(int n){
process(0);
int total = 0, u, w;
3.5 Tarjan: Strongly connected components while (sz(pq)){
ii e = pq.top(); pq.pop();
10

vi low, num, comp, g[nax]; tie(w,v) = e; w*=-1;


int scc, timer; if (!seen[u])
stack<int> st; total += w, process(u);
void tjn(int u) { }
low[u] = num[u] = timer++; st.push(u); int v; return total;
for(int v: g[u]) { }
if(num[v]==-1) tjn(v);
if(comp[v]==-1) low[u] = min(low[u], low[v]);
} 3.8 Dijkstra
if(low[u]==num[u]) {
do{ v = st.top(); st.pop(); comp[v]=scc; // O ((V+E)*log V)
}while(u != v); vector <ii> g[nax];
++scc;
} int d[nax], p[nax];
void dijkstra(int s, int n){

3
}
void callt(int n) { forn(i, n) d[i] = inf, p[i] = -1;

GRAPH ALGORITHMS
timer = scc= 0; d[s] = 0;
num = low = comp = vector<int>(n,-1); priority_queue <ii, vector <ii>,greater<ii> > q;
forn(i,n) if(num[i]==-1) tjn(i); q.push({0, s});
} while(sz(q)){
auto [dist, u] = q.top(); q.pop();
if(dist > d[u]) continue;
for(auto& [v, w]: g[u]){
3.6 MST Kruskal if (d[u] + w < d[v]){
d[v] = d[u] + w;
struct edge{ p[v] = u;
int u, v, w; q.push(ii(d[v], v));
edge(int u, int v, int w): u(u), v(v), w(w){} }
3.9
} ll dist[N];
} int pa[N], cnt[N];
} bool in_q[N];

Bellman-Ford
vi find_path(int t){ bool spfa(int s, int n){
vi path; forn(i, n) dist[i] = (i == s ? 0 : inf);
int cur = t; queue<int> q({s}); in_q[s] = 1;
while(cur != -1){ int start = -1;
path.pb(cur); while(sz(q) && start == -1) {
cur = p[cur]; int u = q.front(); q.pop();
} in_q[u] = 0;
reverse(all(path)); for(auto& [v, w] : g[u]){
return path; if(dist[u] + w < dist[v]) {
} dist[v] = dist[u] + w;
pa[v] = u;
if(!in_q[v]) {
3.9 Bellman-Ford q.push(v);
in_q[v] = 1;
vector<ii> g[nax]; ++cnt[v];
ll dist[nax]; if(cnt[v] > n){ start = v; break; }
bool bellman_ford(int s, int n){ }
forn(i, n) dist[i] = inf; }
}
dist[s] = 0; }
forn(_, n-1){ if(start == -1) return 0;
forn(u, n){ else{ // Si se necesita reconstruir
if(dist[u] == inf) continue; // Unreachable forn(_, n) start = pa[start];
for(auto& [v, w] : g[u]) vi cycle{start};
if(dist[u] + w < dist[v]) dist[v] = dist[u] + w,
11

pa[v] = u; int v = start;


} while(pa[v] != start) v = pa[v], cycle.pb(v);
} cycle.pb(start); // solo si se necesita que vuelva al
int start = -1; start
forn(u, n){ reverse(all(cycle));
return 1;
if(dist[u] == inf) continue; // Unreachable }
for(auto& [v, w] : g[u]) if(dist[u] + w < dist[v]) }
start = v;
}
if(start == -1) return 0;
else{ // Si se necesita reconstruir
forn(_, n) start = pa[start]; 3.11 Floyd-Warshall
vi cycle{start};
int v = start;
// Complejidad O(nˆ3)

3
while(pa[v] != start) v = pa[v], cycle.pb(v);
cycle.pb(start); // solo si se necesita que vuelva al int dist[nax][nax];

GRAPH ALGORITHMS
start void floyd(){
reverse(all(cycle)); // Hay que saber inicializar el array d.
return 1; forn(k,n){
} forn(u,n){
} forn(v,n){
dist[u][v] = min(dist[u][v], dist[u][k] + dist[k
][v]);
}
3.10 Shortest Path Faster Algorithm }
}
// Complexity O(V*E) worst, O(E) on average. }
vector<ii> g[N];
3.12
}
3.12 LCA Binary Lifting bool solve_2SAT() {
int n = 2*N;

LCA Binary Lifting


timer = scc= 0;
const int L = 24; num = low = comp = vi(n,-1);
int timer, up[nax][L+1], n; forn(i,n)
int in[nax], out[nax]; if(num[i]==-1) tjn(i);
vi g[nax]; truth = vector<bool>(N, false);
void dfs(int u, int p){ forn(i,N) {
in[u] = ++timer; if (comp[i] == comp[i + N]) return false;
up[u][0] = p; truth[i] = comp[i] < comp[i + N];
for1(i,L) up[u][i] = up[up[u][i-1]][i-1]; }
for(int v: g[u]){ return true;
if(v==p) continue; }
dfs(v,u); int neg(int x){
} if(x<N) return x+N;
out[u] = ++timer; else return x-N;
} }
bool anc(int u, int v){ void add_edge(int x, int y){
return in[u]<= in[v] && out[u]>= out[v]; g[x].pb(y);
} }
void solve(int root){ void add_disjuntion(int x, int y){
timer = 0; add_edge(neg(x), y);
dfs(root,root); add_edge(neg(y), x);
} }
int lca(int u, int v){ void implies(int x, int y) {
if(anc(u,v)) return u; add_edge(x,y);
12

if(anc(v,u)) return v; add_edge(neg(y),neg(x));


for(int i= L; i>=0; --i){ }
if(!anc(up[u][i],v)) void make_true(int u) { add_edge(neg(u), u); }
u = up[u][i]; void make_false(int u) { make_true(neg(u)); }
} void make_eq(int x, int y){
return up[u][0]; implies(x, y);
} implies(y, x);
}
void make_dif(int x, int y){
3.13 2 SAT implies(neg(x), y);
implies(neg(y), x);
// Complexity O(V+E) }
int N;
vi low, num, comp, g[nax];
vector<bool> truth; 3.14 2 SAT Kosaraju y Tarjan

3
int scc, timer;

GRAPH ALGORITHMS
stack<int> st; // Complexity O(V+E)
void tjn(int u) { // KOSARAJU
low[u] = num[u] = timer++; st.push(u); int v; int N, scc;
for(int v: g[u]) { vi g[2][nax], ts, comp;
if(num[v]==-1) tjn(v); vector<bool> truth;
if(comp[v]==-1) low[u] = min(low[u], low[v]);
} void dfs(int u, int id) {
if(low[u]==num[u]) { if(!id) comp[u] = -2;
do{ v = st.top(); st.pop(); comp[v]=scc; else comp[u] = scc;
}while(u != v); for (int v : g[id][u]){
++scc; if(!id && comp[v]==-1) dfs(v,id);
} else if(id && comp[v]==-2) dfs(v,id);
3.15
} int neg(int x){
if(!id) ts.pb(u); if(x<N) return x+N;
} else return x-N;

Centroid Decomposition
}
bool solve_2SAT() { void add_edge(int x, int y){
int n = 2*N; g[x].pb(y);
comp.assign(n, -1), truth.assign(N, false); }
forn(i,n) if(comp[i]==-1) dfs(i,0); void add_disjuntion(int x, int y){
scc= 0; add_edge(neg(x), y);
forn(i,n){ add_edge(neg(y), x);
int v = ts[n - i - 1]; }
if (comp[v] ==-2) dfs(v,1), ++scc; void implies(int x, int y) {
} add_edge(x,y);
forn(i,N) { add_edge(neg(y),neg(x));
if (comp[i] == comp[i + N]) return false; }
truth[i] = comp[i] > comp[i + N]; void make_true(int u) { add_edge(neg(u), u); }
} void make_false(int u) { make_true(neg(u)); }
return true; void make_eq(int x, int y){
} implies(x, y);
void add_edge(int x, int y){ implies(y, x);
g[0][x].pb(y); }
g[1][y].pb(x); void make_dif(int x, int y){
} implies(neg(x), y);
///////////////////////////////// implies(neg(y), x);
// TARJAN testeado con 2 problemas }
// Complexity O(V+E)
int N;
vi low, num, comp, g[nax];
13

vector<bool> truth; 3.15 Centroid Decomposition


int scc, timer;
stack<int> st;
void tjn(int u) { int cnt[nax], depth[nax], f[nax], dist[25][nax];
low[u] = num[u] = timer++; st.push(u); int v; vi g[nax];
for(int v: g[u]) { int dfs(int u, int dep = -1, bool flag = 0, int dis = 0,
if(num[v]==-1) tjn(v); int p = -1) {
if(comp[v]==-1) low[u] = min(low[u], low[v]); cnt[u] = 1;
} if(flag) dist[dep][u] = dis;
if(low[u]==num[u]) { for (int v : g[u])
do{ v = st.top(); st.pop(); comp[v]=scc; if (!depth[v] && v != p) cnt[u] += dfs(v, dep, flag,
}while(u != v); dis + 1, u);
++scc; return cnt[u];
} }
} int get_centroid (int u, int r, int p = -1) {

3
bool solve_2SAT() { for (int v : g[u])

GRAPH ALGORITHMS
int n = 2*N; if (!depth[v] && v != p && cnt[v] > r)
timer = scc= 0; return get_centroid(v, r, u);
num = low = comp = vi(n,-1); return u;
forn(i,n) if(num[i]==-1) tjn(i); }
truth = vector<bool>(N, false); int decompose(int u, int d = 1) {
forn(i,N) { int centroid = get_centroid(u, dfs(u)>>1);
if (comp[i] == comp[i + N]) return false; depth[centroid] = d;
truth[i] = comp[i] < comp[i + N]; dfs(centroid, d); /// if distances is needed
} for (int v : g[centroid])
return true; if (!depth[v])
} f[decompose(v, d + 1)] = centroid;
return centroid;
3.16
} int v=g[u].front().v;
int lca (int u, int v) { //g[v].erase(g[u].front().rev);
for (; u != v; u = f[u]) g[u].pop_front();

Tree Binarization
if (depth[v] > depth[u]) go(v);
swap(u, v); }
return u; p.push_back(u);
} }
int get_dist(int u, int v){
int dep_l = depth[lca(u,v)]; vi get_path(int u){
return dist[dep_l][u] + dist[dep_l][v]; p.clear();
} go(u);
reverse(all(p));
return p;
}
3.16 Tree Binarization /// for undirected uncomment and check for path existance
bool eulerian(vi &tour) { /// directed graph
vi g[nax]; int one_in = 0, one_out = 0, start = -1;
int son[nax], bro[nax]; bool ok = true;
void binarize(int u, int p = -1){ for (int i = 0; i < n; i++) {
bool flag = 0; int prev = 0; if(out[i] && start == -1) start = i;
for(int v : g[u]){ if(out[i] - in[i] == 1) one_out++, start = i;
if(v == p) continue; else if(in[i] - out[i] == 1) one_in++;
if(flag) bro[prev] = v; else ok &= in[i] == out[i];
else son[u] = v, flag = true; }
binarize(v, u); ok &= one_in == one_out && one_in <= 1;
prev = v; if (ok) {
} tour = get_path(start);
}
14

if(sz(tour) == edges + 1) return true;


}
return false;
3.17 Eulerian Path }

int n;
int edges = 0;
int out[nax], in[nax]; 4 Flows
// Directed version (uncomment commented code for
undirected) 4.1 Edmons-Karp
struct edge {
int v; // Complexity O(V*Eˆ2)
// list<edge>::iterator rev; const ll inf = 1e18;
edge(int v):v(v){}
}; struct EKarp{
list<edge> g[nax]; vector<int> p;
void add_edge(int a, int b){ vector<vector<ll>> cap, flow;
out[a]++; vector<vector<int>> g;
in[b]++; int n, s, t;
++edges; EKarp(int n_){
g[a].push_front(edge(b));//auto ia=g[a].begin(); n = n_; g.resize(n);
// g[b].push_front(edge(a));auto ib=g[b].begin();

4
cap = flow = vector<vector<ll>>(n,vector<ll>(n));
// ia->rev=ib;ib->rev=ia; }

FLOWS
}
vi p; void addEdge(int u, int v, ll c){
void go(int u){ cap[u][v] = c;
while(sz(g[u])){ g[u].pb(v); g[v].pb(u);
4.2
} todo vertices no cubierto hasta el momento, tomar
cualquier arista de el
ll bfs(int s, int t) { // Complexity O(Vˆ2*E)

Dinic
p.assign(n, -1); p[s] = -2; const ll inf = 1e18;
queue<pair<int,ll>> q; struct edge {
q.push(pair<int,ll>(s, inf)); int to, rev; ll cap, f{0};
while (!q.empty()) { edge(int to, int rev, ll cap): to(to), rev(rev), cap(
int u = q.front().fi; ll f = q.front().se; cap){}
q.pop(); };
for(int v: g[u]){ struct Dinic{
if (p[v] == -1 && cap[u][v] - flow[u][v]>0) { int n, s, t; ll max_flow = 0;
p[v] = u; vector<vector<edge>> g;
ll df = min(f, cap[u][v]-flow[u][v]); vi q, dis, work;
if (v == t) return df; Dinic(int n, int s, int t): n(n), s(s), t(t), g(n), q(n
q.push(pair<int,ll>(v, df)); ){}
} void addEdge(int s, int t, ll cap){
} g[s].pb(edge(t, sz(g[t]), cap));
} g[t].pb(edge(s, sz(g[s])-1, 0));
return 0; }
}
ll maxFlow() { bool bfs(){
ll mf = 0; dis.assign(n, -1), dis[s] = 0;
ll f; int qt = 0;
while (f = bfs(s,t)){ q[qt++] = s;
mf += f; forn(qh, qt){
int v = t; int u = q[qh];
while (v != s) { for(auto& [v, _, cap, f]: g[u])
int prev = p[v]; if(dis[v] < 0 && f < cap) dis[v] = dis[u] + 1, q[
15

flow[v][prev] -= f; qt++] = v;
flow[prev][v] += f; }
v = prev; return dis[t] >= 0;
} }
} ll dfs(int u, ll cur){
return mf; if(u == t) return cur;
} for(int& i = work[u]; i < sz(g[u]); ++i){
}; auto& [v, rev, cap, f] = g[u][i];
if(cap <= f) continue;
if(dis[v] == dis[u] + 1){
4.2 Dinic ll df = dfs(v, min(cur, cap - f));
if(df > 0){
// Corte minimo: vertices con dist[v]>=0 (del lado de src f += df, g[v][rev].f -= df;
) VS. dist[v]==-1 (del lado del dst) return df;
// Para el caso de la red de Bipartite Matching (Sean V1 }
y V2 los conjuntos mas proximos a src y dst }
respectivamente): }
return 0;
// Reconstruir matching: para todo v1 en V1 ver las }
aristas a vertices de V2 con it->f>0, es arista del ll maxFlow(){
Matching ll cur_flow = 0;
// Min Vertex Cover: vertices de V1 con dist[v]==-1 + while(bfs()){
vertices de V2 con dist[v]>0

4
work.assign(n, 0);
// Max Independent Set: tomar los vertices NO tomados por while(ll delta = dfs(s, inf)) cur_flow += delta;

FLOWS
el Min Vertex Cover }
// Max Clique: construir la red de G complemento (debe max_flow += cur_flow;
ser bipartito!) y encontrar un Max Independet Set // todos los nodos con dis[u]!=-1 vs los que tienen
// Min Edge Cover: tomar las aristas del matching + para
4.3
dis[v]==-1 forman el min-cut, (u,v) for (int i = 0; i < n; i++)
return max_flow; if (i != s && i != t && excess[i] > 0) {
} if (!max_height.empty() && height[i] > height[

Push-Relabel
vii min_cut(){ max_height[0]])
maxFlow(); max_height.clear();
vii cut; if (max_height.empty() || height[i] == height[
forn(u, n){ max_height[0]])
if(dis[u] == -1) continue; max_height.push_back(i);
for(auto& e: g[u]) if(dis[e.to] == -1) cut.pb({u, e }
.to}); return max_height;
} }
sort(all(cut)), cut.resize(unique(all(cut)) - cut.
begin()); ll maxFlow(){
return cut; height.assign(n,0); excess.assign(n,0);
} ll max_flow = 0; bool pushed;
}; vi current;
height[s] = n; excess[s] = inf;
for(edge &e: g[s])
4.3 Push-Relabel push(s,e);
// Complexity O(Vˆ2 * sqrt(E)) o O(Vˆ3) while(!(current = find_max_height_vertices(s,t)).
const ll inf = 1e17; empty()){
struct PushRelabel{ for(int v: current){
struct edge { pushed = false;
int to, rev; ll f, cap; if(excess[v]==0) continue;
edge(int to, int rev, ll cap, ll f = 0) : to(to), rev for(edge &e : g[v]){
(rev), f(f), cap(cap) {} if(e.cap - e.f>0 && height[v]== height[e.to]+1)
16

}; {
void addEdge(int s, int t, ll cap){ pushed = true;
g[s].pb(edge(t, sz(g[t]), cap)); push(v,e);
g[t].pb(edge(s, sz(g[s])-1, (ll)0)); }
} }
if(!pushed){
int n, s, t; relabel(v);
vi height; vector<ll> excess; break;
vector<vector<edge>> g; }
}
PushRelabel(int n_){ }
n = n_; g.resize(n); for (edge e : g[t]){
} edge rev = g[e.to][e.rev];
void push(int u, edge &e){ max_flow += rev.f;
ll d = min(excess[u], e.cap - e.f); }
edge &rev = g[e.to][e.rev]; return max_flow;
e.f += d; rev.f -= d; }
excess[u] -= d; excess[e.to] += d; };
}
void relabel(int u){
ll d = inf;
for (edge e : g[u]) 4.4 Konig
if (e.cap - e.f > 0)

4
d = min(d,(ll) height[e.to]);
#define sz(c) ((int)c.size())

FLOWS
if (d < inf) height[u] = d + 1; // asume que el dinic YA ESTA tirado
} // asume que nodes-1 y nodes-2 son la fuente y destino
vi find_max_height_vertices(int s, int t) { int match[maxnodes]; // match[v]=u si u-v esta en el
vi max_height; matching, -1 si v no esta matcheado
4.5
int s[maxnodes]; // numero de la bfs del koning
queue<int> kq;
// s[e]%2==1 o si e esta en V1 y s[e]==-1-> lo agarras 4.6 Hungarian Algorithm

MCBM Augmenting Algorithm


void konig() {//O(n)
forn(v,nodes-2) s[v] = match[v] = -1; const ld inf = 1e18; // To Maximize set "inf" to 0, and
forn(v,nodes-2) negate costs
for(edge it: g[v]) inline bool zero(ld x){ return x == 0; } // For Integer/
if (it.to < nodes-2 && it.f>0){ LL --> change to x == 0
match[v]=it.to; match[it.to]=v; struct Hungarian{
} int n; vector<vd> c;
forn(v,nodes-2) vi l, r, p, sn; vd ds, u, v;
if (match[v]==-1){ Hungarian(int n): n(n), c(n, vd(n, inf)), l(n, -1), r(n
s[v]=0;kq.push(v); , -1), p(n), sn(n), ds(n), u(n), v(n){}
} void set_cost(){ forn(i, n) forn(j, n) cin >> c[i][j];
while(!kq.empty()) { }
int e = kq.front(); kq.pop(); ld assign() {
if (s[e]%2==1) { set_cost();
s[match[e]] = s[e]+1; forn(i, n) u[i] = *min_element(all(c[i]))
kq.push(match[e]); ;
} else { forn(j, n){
for(edge it: g[e]) v[j] = c[0][j] - u[0];
if (it.to < nodes-2 && s[it.to]==-1){ for1(i, n-1) v[j] = min(v[j], c[i][j] - u[i]);
s[it->to] = s[e]+1; }
kq.push(it->to); int mat = 0;
} forn(i, n) forn(j, n) if(r[j] == -1 &&
} zero(c[i][j] - u[i] -v[j])){
} l[i] = j, r[j] = i, ++mat; break;
17

} }
for(; mat < n; ++mat){
int s = 0, j = 0, i;
while(l[s] != -1) ++s;
4.5 MCBM Augmenting Algorithm forn(k, n) ds[k] = c[s][k] - u[s] - v[k];
fill(all(p), -1), fill(all(sn), 0);
while(1){
// O (V*E) j = -1;
//Sacado del Vasito forn(k, n) if(!sn[k] && (j == -1 || ds[k] < ds[j
vector<int> g[MAXN]; // [0,n)->[0,m) ])) j = k;
int n,m; sn[j] = 1, i = r[j];
int mat[MAXM];bool vis[MAXN]; if(i == -1) break;
int match(int x){ forn(k, n) if(!sn[k]){
if(vis[x])return 0; auto n_ds = ds[j] + c[i][k] - u[i] - v[k];
vis[x]=true; if(ds[k] > n_ds) ds[k] = n_ds, p[k] = j;
for(int y:g[x])if(mat[y]<0||match(mat[y])){mat[y }
]=x;return 1;} }
return 0; forn(k, n) if(k != j && sn[k]){
} auto dif = ds[k] - ds[j];
vector<pair<int,int> > max_matching(){ v[k] += dif, u[r[k]] -= dif;
vector<pair<int,int> > r; }
memset(mat,-1,sizeof(mat)); u[s] += ds[j];
while(p[j] >= 0) r[j] = r[p[j]], l[r[j]] = j, j =

4
fore(i,0,n)memset(vis,false,sizeof(vis)),match(i)
; p[j];

FLOWS
fore(i,0,m)if(mat[i]>=0)r.pb({mat[i],i}); r[j] = s, l[s] = j;
return r; }
} ld val = 0;
forn(i, n) val += c[i][l[i]];
4.7
return val; while(cur != s){
} int u = g[cur][p[cur]].to, rev = g[cur][p[cur]].
void print_assignment(){ forn(i, n) cout << i+1 << " " rev;

Min-Cost Max-Flow Algorithm


<< l[i]+1 << el; } g[u][rev].f += f, g[cur][p[cur]].f -= f;
}; cur = u;
}
}
if(flow < K) assert(0);
4.7 Min-Cost Max-Flow Algorithm return cost;
}
const ll inf = 1e18; };
struct edge{
int to, rev; ll cap, cos, f{0};
edge(int to, int rev, ll cap, ll cos):to(to), rev(rev), 4.8 Min-Cost Max-Flow Algorithm 2
cap(cap), cos(cos){}
};
struct MCMF{ typedef ll tf;
int n, s, t; typedef ll tc;
vector<vector<edge>> g; const tf INFFLOW=1e9;
vi p; vll dis; const tc INFCOST=1e9;
MCMF(int n): n(n), g(n){} struct MCF{
void addEdge(int s, int t, ll cap, ll cos){ int n;
g[s].pb(edge(t, sz(g[t]), cap, cos)); vector<tc> prio, pot; vector<tf> curflow; vector<
g[t].pb(edge(s, sz(g[s])-1, 0, -cos)); int> prevedge,prevnode;
} priority_queue<pair<tc, int>, vector<pair<tc, int
void spfa(int v0){ >>, greater<pair<tc, int>>> q;
dis.assign(n, inf); dis[v0] = 0; struct edge{int to, rev; tf f, cap; tc cost;};
p.assign(n, -1); vector<vector<edge>> g;
18

vector<bool> inq(n); MCF(int n):n(n),prio(n),curflow(n),prevedge(n),


queue<int> q({v0}); prevnode(n),pot(n),g(n){}
while(sz(q)){ void add_edge(int s, int t, tf cap, tc cost) {
int u = q.front(); q.pop(); g[s].pb((edge){t,sz(g[t]),0,cap,cost});
inq[u] = 0; g[t].pb((edge){s,sz(g[s])-1,0,0,-cost});
for(auto&[v, rev, cap, cos, f] : g[u]){ }
if(cap - f > 0 && dis[v] > dis[u] + cos){ pair<tf,tc> get_flow(int s, int t) {
dis[v] = dis[u] + cos, p[v] = rev; tf flow=0; tc flowcost=0;
if(!inq[v]) inq[v] = 1, q.push(v); while(1){
} q.push({0, s});
} fill(all(prio),INFCOST);
} prio[s]=0; curflow[s]=INFFLOW;
} tc d; int u;
ll min_cos_flow(ll K){ while(sz(q)){
ll flow = 0, cost = 0; tie(d,u)=q.top(); q.pop()
while(flow < K){ ;
spfa(s); if(d!=prio[u]) continue;
if(dis[t] == inf) break; forn(i,sz(g[u])) {
ll f = K - flow; edge &e=g[u][i];
int cur = t; // Find flow int v=e.to;
while(cur != s){ if(e.cap<=e.f)
int u = g[cur][p[cur]].to, rev = g[cur][p[cur]]. continue;
tc nprio=prio[u]+

4
rev;
f = min(f, g[u][rev].cap - g[u][rev].f); e.cost+pot[u]-

FLOWS
cur = u; pot[v];
} if(prio[v]>nprio)
flow += f, cost += f * dis[t], cur = t; // {
Apply flow prio[v]=
4.9
nprio; void add_edge(int u, int v) {
q.push({ if(ed[u][v]) return;
nprio, ed[u][v] = 1;

Blossom
v}); top->v = v, top->n = adj[u], adj[u] = top++;
prevnode[ top->v = u, top->n = adj[v], adj[v] = top++;
v]=u; }
prevedge int get_lca(int root, int u, int v) {
[v]=i; fill(inp.begin(), inp.end(), 0);
curflow[v while(1) {
]=min( inp[u = base[u]] = 1;
curflow if(u == root) break;
[u], e u = f[ match[u] ];
.cap-e }
.f); while(1) {
} if(inp[v = base[v]]) return v;
} else v = f[ match[v] ];
} }
if(prio[t]==INFCOST) break; }
forn(i,n) pot[i]+=prio[i]; void mark(int lca, int u) {
tf df=min(curflow[t], INFFLOW- while(base[u] != lca) {
flow); int v = match[u];
flow+=df; inb[ base[u ]] = 1;
for(int v=t; v!=s; v=prevnode[v]) inb[ base[v] ] = 1;
{ u = f[v];
edge &e=g[prevnode[v]][ if(base[u] != lca) f[u] = v;
prevedge[v]]; }
e.f+=df; g[v][e.rev].f-= }
df;
19

flowcost+=df*e.cost; void blossom_contraction(int s, int u, int v) {


} int lca = get_lca(s, u, v);
} fill(all(inb), 0);
return {flow,flowcost}; mark(lca, u); mark(lca, v);
} if(base[u] != lca) f[u] = v;
}; if(base[v] != lca) f[v] = u;
forn(u,n){
if(inb[base[u]]) {
base[u] = lca;
4.9 Blossom if(!inq[u]) {
inq[u] = 1;
/// Complexity: O(|E||V|ˆ2) q.push(u);
/// Tested: https://tinyurl.com/oe5rnpk }
/// Max matching undirected graph }
struct network { }
struct struct_edge { int v; struct_edge * n; }; }
typedef struct_edge* edge; int bfs(int s) {
int n; fill(all(inq), 0);
struct_edge pool[MAXE]; ///2*n*n; fill(all(f), -1);
edge top; for(int i = 0; i < n; i++) base[i] = i;
vector<edge> adj; q = queue<int>();
queue<int> q; q.push(s);
vector<int> f, base, inq, inb, inp, match; inq[s] = 1;

4
vector<vector<int>> ed; while(sz(q)) {

FLOWS
network(int n) : n(n), match(n, -1), adj(n), top(pool), int u = q.front(); q.pop();
f(n), base(n), for(edge e = adj[u]; e; e = e->n) {
inq(n), inb(n), inp(n), ed(n, vector< int v = e->v;
int>(n)) {} if(base[u] != base[v] && match[u] != v) {
if((v == s) || (match[v] != -1 && f[match[v]]
!= -1)) 5.2 SQRT Decomposition
blossom_contraction(s, u, v);
else if(f[v] == -1) {
f[v] = u; // Complexity: 1. Preprocessing O(n)
if(match[v] == -1) return v; // 2. Update O(1) 3. Query O(n/sqrt(n) + sqrt(n))
else if(!inq[match[v]]) { struct sqrt_decomp{
inq[match[v]] = 1; int n, len; vi a, b;
q.push(match[v]); sqrt_decomp(){}
} sqrt_decomp(vi& arr): n(sz(arr)), len(sqrt(n) + 1), a(
} arr), b(len){
} forn(i, n) b[i / len] += a[i];
} }
} void update(int pos, int val){
return -1; b[pos / len] += val - a[pos]; // Block update
} a[pos] = val; // Point update
int doit(int u) { }
if(u == -1) return 0; int query(int l, int r){
int v = f[u]; int sum = 0, b_l = l / len, b_r = r / len;
doit(match[v]); if(b_l == b_r) fore(i,l,r) sum += a[i]; // L, R in
match[v] = u; match[u] = v; same block
return u != -1; else{
} fore(i, l, len*(b_l+1) - 1) sum += a[i]; // Left
/// (i < net.match[i]) => means match Tail (Points)
int maximum_matching() { fore(i, len*b_r, r) sum += a[i]; // Right Tail (
int ans = 0; Points)
forn(u,n) fore(i, b_l+1, b_r-1) sum += b[i]; // Block query
20

ans += (match[u] == -1) && doit(bfs(u)); }


return ans; return sum;
} }
}; };

5.3 Fenwick Tree


5 Data Structures
struct fwtree{ // 0-indexed
5.1 Disjoint Set Union int n; vi bit;
fwtree(int n): n(n), bit(n+1){}
int rsq(int r){ // [0, r]
struct dsu{ int sum = 0;
vi p, r; int comp; for(++r; r; r -= r & -r) sum += bit[r];
dsu(int n): p(n), r(n, 1), comp(n){iota(all(p), 0);} return sum;

5
int find_set(int i){return p[i] == i ? i : p[i] = }
find_set(p[i]);} int rsq(int l, int r){return rsq(r) - (l==0 ? 0 : rsq(l

DATA STRUCTURES
bool is_same_set(int i, int j){return find_set(i) == -1));}
find_set(j);} void upd(int r, int v){
void union_set(int i, int j){ for(++r; r <= n; r += r & -r) bit[r] += v;
}
if((i = find_set(i)) == (j = find_set(j))) return; };
if(r[i] > r[j]) swap(i, j);
r[j] += r[i]; r[i] = 0;
p[i] = j; --comp;
} 5.4 Fenwick Tree 2D
};
struct fwtree{ // 0-indexed
5.5
int n, m; vector<vll> bit;
fwtree(){}
fwtree(int n, int m): n(n), m(m), bit(n+1, vll(m+1, 0)) 5.6 ST Lazy Propagation

Segment Tree
{}
ll sum(int x, int y) { // [0, x], [0, y] const int N = 1e5 + 10;
ll v = 0; int t[N << 2], lazy[N << 2];
for(int i = x+1; i; i -= i & -i) struct stree{
for(int j = y+1; j; j -= j & -j) v += bit[i][j]; int n, l, r, val, neutro = 0;
return v; stree(int n): n(n){ forn(i, n << 2) t[i] = lazy[i] = 0;
} }
void add(int x, int y, ll dt) { stree(vector<int> &a){ n = sz(a); forn(i, n << 2) t[i]
for(int i = x+1; i <= n; i += i & -i) = lazy[i] = 0;
for(int j = y+1; j <= m; j += j & -j) bit[i][j] += build(1, 0, n-1, a);
dt; }
} inline int oper(int a, int b){ return a > b ? a : b; }
}; inline void push(int v){
if(lazy[v]){
t[v << 1] += lazy[v]; lazy[v << 1] += lazy[v];
5.5 Segment Tree t[(v << 1) | 1] += lazy[v]; lazy[(v << 1) | 1] +=
lazy[v];
lazy[v] = 0;
struct stree{ }
int neutro = 1e9, n, l, r, pos, val; vi t; }
stree(int n): n(n), t(n << 2){} void build(int v, int tl, int tr, vi& a){
stree(const vi& a): n(sz(a)), t(n<<2){ build(1, 0, n-1, if(tl == tr){
a); } t[v] = a[tl]; return;
inline int oper(int a, int b){ return a < b ? a : b; } }
21

void build(int v, int tl, int tr, const vi& a){// solo int tm = (tl + tr) >> 1;
para el 2. constructor build(v << 1, tl, tm, a), build((v << 1) | 1, tm+1,
if(tl == tr){ t[v] = a[tl]; return; } tr, a);
int tm = (tl + tr) >> 1; t[v] = oper(t[v << 1], t[(v << 1) | 1]);
build(v << 1, tl, tm, a), build((v << 1) | 1, tm+1, }
tr, a); void upd(int v, int tl, int tr){
t[v] = oper(t[v << 1], t[(v << 1) | 1]); if(tl > r || tr < l) return;
} if(l <= tl && tr <= r){
int query(int v, int tl, int tr){ t[v] += val; lazy[v] += val;
if(tl > r || tr < l) return neutro; // estoy fuera return ;
if(l <= tl && tr <= r) return t[v]; }
int tm = (tl + tr) >> 1; push(v); int tm = (tl + tr) >> 1;
return oper(query(v << 1, tl, tm), query((v << 1) | upd(v << 1, tl, tm); upd((v << 1) | 1, tm+1, tr);
1, tm+1, tr)); t[v] = oper(t[v << 1], t[(v << 1) | 1]);
} }

5
void upd(int v, int tl, int tr){ int query(int v, int tl, int tr){
if(tl == tr){ t[v] = val; return; } if(tl > r || tr < l) return neutro;

DATA STRUCTURES
int tm = (tl + tr) >> 1; if(l <= tl && tr <= r) return t[v];
if(pos <= tm) upd(v << 1, tl, tm); push(v); int tm = (tl + tr) >> 1;
else upd((v << 1) | 1, tm+1, tr); return oper(query(v << 1, tl, tm), query((v << 1) |
t[v] = oper(t[v << 1], t[(v << 1) | 1]); 1, tm + 1, tr));
} }
void upd(int idx, int num){ pos = idx, val = num, upd void update(int ql, int qr, int qval){
(1, 0, n-1);} l = ql, r = qr, val = qval, upd(1, 0, n-1); }
int query(int ql, int qr){ l = ql, r = qr; return int query(int ql, int qr){ l = ql, r = qr; return
query(1, 0, n-1);} query(1, 0, n-1); }
}; };
5.7
inline ll op(ll a, ll b){ return a+b; }
5.7 Persistent ST void build(vector<vi>& a){
forn(i, n) forn(j, m) st[i+n][j+m] = a[i][j];

Persistent ST
const int len = 1e7, neutro = 1e9; forn(i, n) fored(j, 1, m-1) st[i+n][j] = op(st[i+n][j
struct node{ int mn, l, r; }; <<1], st[i+n][j<<1|1]);
struct stree{ fored(i, 1, n-1) forn(j, 2*m) st[i][j] = op(st[i<<1][
vi rts{0}; vector<node> t; j], st[i<<1|1][j]);
int n, idx{0}, l, r, pos, val; }
inline int oper(int a, int b){ return a < b ? a : b; } void upd(int x, int y, ll v){
stree(const vi &a): n(sz(a)), t(len){ build(0, n-1, a); st[x+n][y+m] = v;
} for(int j = y+m; j > 1; j >>= 1) st[x+n][j>>1] = op(
int build(int tl, int tr, const vi &a){ st[x+n][j], st[x+n][jˆ1]);
int v = idx++; for(int i = x+n; i > 1; i >>= 1)
if(tl == tr){ t[v].mn = a[tl]; return v; } for(int j = y+m; j; j >>= 1) st[i>>1][j] = op(st[i
int tm = (tl + tr) >> 1; ][j], st[iˆ1][j]);
t[v].l = build(tl, tm, a), t[v].r = build(tm + 1, tr }
, a); ll query(int x0, int x1, int y0, int y1){ // [x0, x1],
t[v].mn = oper(t[t[v].l].mn, t[t[v].r].mn); [y0, y1]
return v; ll r = neutro;
} for(int i0 = x0+n, i1 = x1+n+1; i0 < i1; i0 >>= 1, i1
int que(int v, int tl, int tr){ >>= 1){
if(tl > r || tr < l) return neutro; int t[4], q=0;
if(l <= tl && tr <= r) return t[v].mn; if(i0&1) t[q++] = i0++;
int tm = (tl + tr) >> 1; if(i1&1) t[q++] = --i1;
return oper(que(t[v].l, tl, tm), que(t[v].r, tm + 1, forn(k, q) for(int j0 = y0+m, j1 = y1+m+1; j0 < j1;
tr)); j0 >>= 1, j1 >>= 1){
} if(j0&1) r = op(r, st[t[k]][j0++]);
22

int upd(int prv, int tl, int tr){ if(j1&1) r = op(r, st[t[k]][--j1]);
int v = idx++; }
t[v] = t[prv]; }
if(tl == tr){ t[v].mn = val; return v; } return r;
int tm = (tl + tr) >> 1; }
if(pos <= tm) t[v].l = upd(t[v].l, tl, tm); };
else t[v].r = upd(t[v].r, tm + 1, tr);
t[v].mn = oper(t[t[v].l].mn, t[t[v].r].mn);
return v; 5.9 Segtree iterativo
}
int query(int v, int cl, int cr){ l = cl, r = cr; const int N = 1e5; // limit for array size
return que(v, 0, n-1); } int t[2 * N];
void upd(int i, int x){ pos = i, val = x, rts.pb(upd( struct stree{
rts.back(), 0, n-1)); } int n, neutro = 1e9;
}; stree(int n): n(n){ forn(i, 2*n) t[i] = neutro; }

5
stree(vi a): n(sz(a)){ build(a); }
inline int op(int a, int b){ return min(a, b); }

DATA STRUCTURES
5.8 Segtree 2D void build(vi& a) {
forn(i, n) t[n + i] = a[i];
const int N = 2500 + 1; fored(i, 1, n-1) t[i] = op(t[i<<1], t[i<<1|1]);
ll st[2*N][2*N]; }
struct stree{ int query(int l, int r) { // [l, r]
int n, m, neutro = 0; int vl = neutro, vr = neutro;
stree(int n, int m): n(n), m(m){ forn(i, 2*n) forn(j, for(l += n, r += n+1; l < r; l >>= 1, r >>= 1) {
2*m) st[i][j] = neutro; } if(l&1) vl = op(vl, t[l++]);
stree(vector<vi> a): n(sz(a)), m(n ? sz(a[0]) : 0){ if(r&1) vr = op(t[--r], vr);
build(a); } }
5.10
return op(vl, vr); void add(int u, int x) { /// x == 1 add, x == -1 delete
} cnt[u] += x;
void upd(int p, int val) { // set val at position p (0 }

RMQ
- idx) void dfs(int u, int p, bool keep = true){
for (t[p += n] = val; p > 1; p >>= 1) t[p>>1] = op(t[ for(int v: g[u])
p], t[pˆ1]); if(v!=p && v!=big[u])
} dfs(v,u, 0);
}; if(big[u]!=-1) dfs(big[u], u);
/// add all small
for(int v: g[u])
5.10 RMQ if(v!=p && v!=big[u])
for(int i = fr[v]; i<= to[v]; ++i)
add(who[i],1);
const int N = 1e5 + 10, K = 20; //K has to satisfy K> add(u,1);
log nax + 1 /// Answer queries
ll st[N][K]; if(!keep)
struct RMQ{ for(int i = fr[u]; i<= to[u]; ++i)
ll neutro = inf; add(who[i],-1);
inline ll oper(ll a, ll b){ return a < b ? a : b; } }
RMQ(vi& a){ void solve(int root){
forn(i, sz(a)) st[i][0] = a[i]; timer = 0;
for1(j, K-1) pre(root, root);
forn(i, sz(a) - (1 << j) + 1) dfs(root, root);
st[i][j] = oper(st[i][j-1], st[i + (1 << (j-1))][ }
j-1]);
}
ll query(int l, int r){
5.12 Heavy Light Decomposition
23

if(l > r) return neutro;


int j = 31 - __builtin_clz(r-l+1);
return oper(st[l][j], st[r - (1 << j) + 1][j]); vector<int> g[nax];
}
}; int len[nax], dep[nax], in[nax], out[nax], head[nax], par
[nax], idx;
void dfs_sz( int u, int d ) {
dep[u] = d;
5.11 Sack int &sz = len[u]; sz = 1;
for( auto &v : g[u] ) {
// Time Complexity O(N*log(N)) if( v == par[u] ) continue;
int timer; par[v] = u; dfs_sz(v, d+1);
int cnt[nax], big[nax], fr[nax], to[nax], who[nax]; sz += len[v];
vector<int> g[nax]; if(len[ g[u][0] ] < len[v]) swap(g[u][0], v);
int pre(int u, int p){ }
int sz = 1, tmp; return ;
who[timer] = u; }

5
fr[u] = timer++; void dfs_hld( int u) {

DATA STRUCTURES
ii best = {-1, -1}; in[u] = idx++;
for(int v: g[u]){ arr[in[u]] = val[u]; /// to initialize the segment tree
if(v==p) continue; for( auto& v : g[u] ) {
tmp = pre(v,u); if( v == par[u] ) continue;
sz+=tmp; head[v] = (v == g[u][0] ? head[u] : v);
best = max(best, {tmp, v}); dfs_hld(v);
} }
big[u] = best.se; out[u] = idx-1;
to[u] = timer-1; }
return sz; void upd_hld( int u, int val ) {
} upd_DS(in[u], val);
5.13
} }
int query_hld( int u, int v ) { void erase(pitem& t, int key){
int val = neutro; if(t->key==key)merge(t,t->l,t->r);

Treap
while( head[u] != head[v] ) { else erase(key<t->key?t->l:t->r,key);
if( dep[ head[u] ] < dep[ head[v] ] ) swap(u, v); upd_cnt(t);
val = val + query_DS(in[ head[u] ], in[u]); }
u = par[ head[u] ]; void unite(pitem &t, pitem l, pitem r){
} if(!l||!r){t=l?l:r;return;}
if( dep[u] > dep[v] ) swap(u, v); if(l->pr<r->pr)swap(l,r);
val = val+query_DS(in[u], in[v]); pitem p1,p2;split(r,l->key,p1,p2);
return val; unite(l->l,l->l,p1);unite(l->r,l->r,p2);
/// when updates are on edges use: (line 36) t=l;upd_cnt(t);
/// if (dep[u] == dep[v]) return val; }
/// val = val+query_DS(in[u] + 1, in[v]); pitem kth(pitem t, int k){
} if(!t)return 0;
void build(int root) { if(k==cnt(t->l))return t;
idx = 0; /// DS index [0, n) return k<cnt(t->l)?kth(t->l,k):kth(t->r,k-cnt(t->
par[root] = head[root] = root; l)-1);
dfs_sz(root, 0); }
dfs_hld(root); pair<int,int> lb(pitem t, int key){ // position and value
/// initialize DS of lower_bound
} if(!t)return {0,1<<30}; // (special value)
if(key>t->key){
auto w=lb(t->r,key);w.fst+=cnt(t->l)+1;
5.13 Treap return w;
}
auto w=lb(t->l,key);
24

typedef struct item *pitem; if(w.fst==cnt(t->l))w.snd=t->key;


struct item { return w;
int pr,key,cnt; }
pitem l,r;
item(int key):key(key),pr(rand()),cnt(1),l(0),r
(0) {} 5.14 Implicit Treap
};
int cnt(pitem t){return t?t->cnt:0;}
void upd_cnt(pitem t){if(t)t->cnt=cnt(t->l)+cnt(t->r)+1;} // example that supports range reverse and addition
void split(pitem t, int key, pitem& l, pitem& r){ // l: < updates, and range sum query
key, r: >= key // (commented parts are specific to this problem)
if(!t)l=r=0; typedef struct item* pitem;
else if(key<t->key)split(t->l,key,l,t->l),r=t; struct item {
else split(t->r,key,t->r,r),l=t; int pr,cnt,val;
upd_cnt(t); // int sum; // (paramters for range query)
} // bool rev;int add; // (parameters for lazy prop)

5
void insert(pitem& t, pitem it){ pitem l,r;
if(!t)t=it;

DATA STRUCTURES
item(int val): pr(rand()),cnt(1),val(val),l(0),r
else if(it->pr>t->pr)split(t,it->key,it->l,it->r) (0)/*,sum(val),rev(0),add(0)*/ {}
,t=it; };
else insert(it->key<t->key?t->l:t->r,it); void push(pitem it){
upd_cnt(t); if(it){
} /*if(it->rev){
void merge(pitem& t, pitem l, pitem r){ swap(it->l,it->r);
if(!l||!r)t=l?l:r; if(it->l)it->l->revˆ=true;
else if(l->pr>r->pr)merge(l->r,l->r,r),t=l; if(it->r)it->r->revˆ=true;
else merge(r->l,l,r->l),t=r; it->rev=false;
upd_cnt(t); }
5.15
it->val+=it->add;it->sum+=it->cnt*it->add push(t);
; if(sz<=cnt(t->l)){
if(it->l)it->l->add+=it->add; split(t->l,l,t->l,sz);r=t;

Implicit Treap Father


if(it->r)it->r->add+=it->add; if(l)l->f=0;
it->add=0;*/ if(t->l)t->l->f=t;
} }
} else {
int cnt(pitem t){return t?t->cnt:0;} split(t->r,t->r,r,sz-1-cnt(t->l));l=t;
// int sum(pitem t){return t?push(t),t->sum:0;} if(r)r->f=0;
void upd_cnt(pitem t){ if(t->r)t->r->f=t;
if(t){ }
t->cnt=cnt(t->l)+cnt(t->r)+1; upd_cnt(t);
// t->sum=t->val+sum(t->l)+sum(t->r); }
} void push_all(pitem t){
} if(t->f)push_all(t->f);
void merge(pitem& t, pitem l, pitem r){ push(t);
push(l);push(r); }
if(!l||!r)t=l?l:r; pitem root(pitem t, int& pos){ // get root and position
else if(l->pr>r->pr)merge(l->r,l->r,r),t=l; for node t
else merge(r->l,l,r->l),t=r; push_all(t);
upd_cnt(t); pos=cnt(t->l);
} while(t->f){
void split(pitem t, pitem& l, pitem& r, int sz){ // sz: pitem f=t->f;
desired size of l if(t==f->r)pos+=cnt(f->l)+1;
if(!t){l=r=0;return;} t=f;
push(t); }
if(sz<=cnt(t->l))split(t->l,l,t->l,sz),r=t; return t;
25

else split(t->r,t->r,r,sz-1-cnt(t->l)),l=t; }
upd_cnt(t);
}
void output(pitem t){ // useful for debugging
if(!t)return;
push(t); 5.16 Ordered Set
output(t->l);printf(" %d",t->val);output(t->r);
}
// use merge and split for range updates and queries #include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
typedef tree<int, null_type, less<int>, rb_tree_tag,
5.15 Implicit Treap Father tree_order_statistics_node_update> ordered_set;
// -------- CONSTRUCTOR -------- //
// node father is useful to keep track of the chain of // 1. Para ordenar por MAX cambiar less<int> por greater<
each node int>

5
// alternative: splay tree // 2. Para multiset cambiar less<int> por less_equal<int>
// IMPORTANT: add pointer f in struct item // Para borrar siendo multiset:

DATA STRUCTURES
void merge(pitem& t, pitem l, pitem r){ // int idx = st.order_of_key(value);
push(l);push(r); // st.erase(st.find_by_order(idx));
if(!l||!r)t=l?l:r; // -------- METHODS --------- //
else if(l->pr>r->pr)merge(l->r,l->r,r),l->r->f=t= st.find_by_order(k) // returns pointer to the k-th
l; smallest element
else merge(r->l,l,r->l),r->l->f=t=r; st.order_of_key(x) // returns how many elements are
upd_cnt(t); smaller than x
} st.find_by_order(k) == st.end() // true, if element does
void split(pitem t, pitem& l, pitem& r, int sz){ not exist
if(!t){l=r=0;return;}
5.17
struct DynCon {
vector<Query> q; dsu uf;
5.17 Mo’s Algorithm vi mt; map<ii, int> prv;

Mo’s Algorithm
DynCon(int n): uf(n){}
/// Complexity: O(|N+Q|*sqrt(|N|)*|ADD/DEL|) void add(int i, int j){
/// Requires add(), delete() and get_ans() if(i > j) swap(i, j);
struct query { q.pb({ADD, i, j}); mt.pb(-1);
int l, r, idx; prv[{i, j}] = sz(q)-1;
}; }
int S; // s = sqrt(n) void remove(int i, int j){
bool cmp (query a, query b) { if(i > j) swap(i, j);
int x = a.l/S; q.pb({DEL, i, j});
if (x != b.l/S) return x < b.l/S; int pr = prv[{i, j}];
return (x&1 ? a.r < b.r : a.r > b.r); mt[pr] = sz(q)-1; mt.pb(pr);
} }
void solve(){ void query(){ q.pb({QUERY, -1, -1}); mt.pb(-1);}
S = sqrt(n); // n = size of array void process(){ // answers all queries in order
sort(all(q), cmp); if(!sz(q)) return;
int l = 0, r = -1; forn(i, sz(q)) if(q[i].type == ADD && mt[
forn(i, sz(q)){ i] < 0) mt[i] = sz(q);
while (r < q[i].r) add(++r); go(0, sz(q));
while (l > q[i].l) add(--l); }
while (r > q[i].r) del(r--); void go(int s, int e){
while (l < q[i].l) del(l++); if(s+1 == e){
ans[q[i].idx] = get_ans(); if(q[s].type == QUERY) cout << uf
} .comp << el;
} return;
26

}
int k = sz(uf.c), m = (s+e)/2;
fored(i, m, e-1) if(mt[i] >= 0 && mt[i] <
5.18 Dynamic Connectivity s) uf.union_set(q[i].u, q[i].v);
go(s, m); uf.rollback(k);
struct dsu { fored(i, s, m-1) if(mt[i] >= e) uf.union_set(q[i].u,
vi p, r, c; int comp; q[i].v);
dsu(int n): p(n), r(n, 1), comp(n){iota(all(p), go(m, e); uf.rollback(k);
0);} }
};
int find_set(int i){return i == p[i] ? i :
find_set(p[i]);}
void union_set(int i, int j){
if((i = find_set(i)) == (j = find_set(j)) 5.19 Link Cut Tree
) return;
if(r[i] > r[j]) swap(i, j);
struct Node { // Splay tree. Root’s pp contains tree’s

5
r[j] += r[i]; c.pb(i);
p[i] = j; --comp; parent.

DATA STRUCTURES
} Node *p = 0, *pp = 0, *c[2] = {0, 0};
void rollback(int snap){ bool flip = 0;
while(sz(c) > snap){ Node(){}
int x = c.back(); c.pop_back(); void fix() { forn(i, 2) if(c[i]) c[i]->p = this; }
r[p[x]] -= r[x]; p[x] = x; ++ inline int up() { return p ? p->c[1] == this : -1; }
comp; void push() {
} if (!flip) return;
} flip = 0, swap(c[0], c[1]);
}; forn(i, 2) if(c[i]) c[i]->flip ˆ= 1;
enum {ADD, DEL, QUERY}; }
struct Query {int type, u, v;}; void rot(int i, int b) {
int h = i ˆ b; void makeRoot(Node* u) { /// Move u to root of
Node *x = c[i], *y = b == 2 ? x : x->c[h], *z = b ? represented tree.
y : x; get(u), u->splay();
if ((y->p = p)) p->c[up()] = y; if(u->c[0]) {
c[i] = z->c[iˆ1]; u->c[0]->p = 0;
if(b < 2) x->c[h] = y->c[hˆ1], z->c[hˆ1] = b ? x : u->c[0]->flip ˆ= 1;
this; u->c[0]->pp = u;
y->c[iˆ1] = b ? this : x; u->c[0] = 0, u->fix();
fix(), x->fix(), y->fix(); }
if(p) p->fix(); }
swap(pp, y->pp); };
}
void splay() { // Splay *this up to the root. Finishes
without flip set.
for(push(); p; ) { 6 Math
if(p->p) p->p->push();
p->push(), push();
int c1 = up(), c2 = p->up(); 6.1 Sieve of Eratosthenes
if(c2 == -1) p->rot(c1, 2);
else p->p->rot(c2, c1 != c2); // O(n)
} // pr contains prime numbers
} // lp[i] == i if i is prime
Node* first() { return push(), c[0] ? c[0]->first() : ( // else lp[i] is minimum prime factor of i
splay(), this); } const int nax = 1e7;
}; // Return the MIN of the subtree rooted at this, int lp[nax+1];
splayed to the top. vector<int> pr; // It can be sped up if change for an
array
struct LinkCut {
27

vector<Node> node; void sieve(){


LinkCut(int n) : node(n) {} fore(i,2,nax-1){
Node* get(Node* u) { /// Move u to root aux tree. if (lp[i] == 0) {
u->splay(); lp[i] = i; pr.pb(i);
while (Node* pp = u->pp) { }
pp->splay(), u->pp = 0; for (int j=0, mult= i*pr[j]; j<sz(pr) && pr[j]<=lp[i]
if(pp->c[1]) pp->c[1]->p = 0, pp->c[1]->pp = pp; && mult<nax; ++j, mult= i*pr[j])
pp->c[1] = u, pp->fix(), u = pp; lp[mult] = pr[j];
} }
return u; // Return the root of the root aux tree. }
}
bool connected(int u, int v) { // are u, v in the same
tree?
return get(&node[u])->first() == get(&node[v])->first 6.2 Count primes
();
} int count_primes(int n) {
void link(int u, int v) { // add an edge (u, v) const int S = 10000;
assert(!connected(u, v)), makeRoot(&node[u]), node[ vector<int> primes;
u].pp = &node[v]; int nsqrt = sqrt(n);
} vector<char> is_prime(nsqrt + 1, true);
void cut(int u, int v) { // remove an edge (u, v) fore(i,2,nsqrt){
Node *x = &node[u], *top = &node[v]; if (is_prime[i]) {
makeRoot(top), x->splay(), assert(top == (x->pp ? : primes.pb(i);

6
x->c[0])); for (int j = i * i; j <= nsqrt; j += i)
if(x->pp) x->pp = 0;

MATH
is_prime[j] = false;
else x->c[0] = top->p = 0, x->fix(); }
} }
6.3
int result = 0;
vector<char> block(S); forn(c,grado1+grado2+1) ans[c] = 0;
for (int k = 0; k * S <= n; k++) { forn(pos,grado1+1){

Segmented Sieve
fill(all(block), true); forn(ter,grado2+1)
int start = k * S; ans[pos + ter] += pol1[pos] * pol2[ter];
for (int p : primes) { }
int start_idx = (start + p - 1) / p;
int j = max(start_idx, p) * p - start;
for (; j < S; j += p) 6.5 Fast Fourier Transform
block[j] = false;
} typedef double ld;
if (k == 0) const ld PI = acos(-1.0L);
block[0] = block[1] = false; const ld one = 1;
for (int i = 0; i < S && start + i <= n; i++) {
if (block[i]) typedef complex<ld> C;
result++; typedef vector<ld> vd;
} void fft(vector<C>& a) {
} int n = sz(a), L = 31 - __builtin_clz(n);
return result; static vector<complex<ld>> R(2, 1);
} static vector<C> rt(2, 1); // (ˆ 10% faster if
double)
for (static int k = 2; k < n; k *= 2) {
6.3 Segmented Sieve R.resize(n); rt.resize(n);
auto x = polar(one, PI / k);
// Complexity O((R-L+1)*log(log(R)) + sqrt(R)*log(log(R)) fore(i,k,2*k-1) rt[i] = R[i] = i&1 ? R[i
) /2] * x : R[i/2];
}
28

// R-L+1 roughly 1e7 R-- 1e12 vi rev(n);


vector<bool> segmentedSieve(ll L, ll R) {
// generate all primes up to sqrt(R) forn(i,n) rev[i] = (rev[i / 2] | (i & 1) << L) /
ll lim = sqrt(R); 2;
vector<bool> mark(lim + 1, false); forn(i,n) if (i < rev[i]) swap(a[i], a[rev[i]]);
vector<ll> primes; for (int k = 1; k < n; k *= 2)
for (ll i = 2; i <= lim; ++i) { for (int i = 0; i < n; i += 2 * k) forn(j
if (!mark[i]) { ,k) {
primes.emplace_back(i); // C z = rt[j+k] * a[i+j+k]; //
for (ll j = i * i; j <= lim; j += i) (25% faster if hand-rolled)
mark[j] = true; /// include-line
} auto x = (ld *)&rt[j+k], y = (ld
} *)&a[i+j+k]; ///
vector<bool> isPrime(R - L + 1, true); exclude-line
for (ll i : primes) C z(x[0]*y[0] - x[1]*y[1], x[0]*y
for (ll j = max(i * i, (L + i - 1) / i * i); j <= R; [1] + x[1]*y[0]); //
j += i) / exclude-line
isPrime[j - L] = false; a[i + j + k] = a[i + j] - z;
if (L == 1) a[i + j] += z;
isPrime[0] = false; }
return isPrime; }
} typedef vector<ll> vl;

6
vl conv(const vl& a, const vl& b) {
if (a.empty() || b.empty()) return {};
6.4 Polynomial Multiplication

MATH
vl res(sz(a) + sz(b) - 1);
int L = 32 - __builtin_clz(sz(res)), n = 1 << L;
int ans[grado1+grado2+1]; vector<C> in(n), out(n);
6.6
copy(all(a), begin(in)); //else p[i+j]=v,p[i+l+j]=u-v;
forn(i,sz(b)) in[i].imag(b[i]); }
fft(in); }

FHT
for (C& x : in) x *= x; // like polynomial multiplication, but XORing exponents
forn(i,n) out[i] = in[-i & (n - 1)] - conj(in[i]) // instead of adding them (also ANDing, ORing)
; vector<ll> multiply(vector<ll>& p1, vector<ll>& p2){
fft(out); int n=1<<(32-__builtin_clz(max(sz(p1),sz(p2))-1))
forn(i,sz(res)) res[i] = floor(imag(out[i]) / (4 ;
* n) +0.5); forn(i,n)c1[i]=0,c2[i]=0;
return res; forn(i,sz(p1))c1[i]=p1[i];
} forn(i,sz(p2))c2[i]=p2[i];
vl convMod(const vl &a, const vl &b, const int &M) { fht(c1,n,false);fht(c2,n,false);
forn(i,n)c1[i]*=c2[i];
if (a.empty() || b.empty()) return {}; fht(c1,n,true);
vl res(sz(a) + sz(b) - 1); return vector<ll>(c1,c1+n);
int B=32-__builtin_clz(sz(res)), n=1<<B, cut=int( }
sqrt(M));
vector<C> L(n), R(n), outs(n), outl(n);
forn(i,sz(a)) L[i] = C((int)a[i] / cut, (int)a[i] 6.7 Fibonacci Matrix
% cut);
forn(i,sz(b)) R[i] = C((int)b[i] / cut, (int)b[i] pll fib_log(ll n, ll mod){
% cut);
fft(L), fft(R); if (n == 0) return {0, 1};
forn(i,n) { auto [a, b] = fib_log(n >> 1, mod);
int j = -i & (n - 1); ll c = a * (2*b - a + mod) % mod;
outl[j] = (L[i] + conj(L[j])) * R[i] / ll d = ((a*a % mod) + (b*b % mod)) % mod;
(2.0 * n); if (n & 1) return {d, (c + d) % mod};
outs[j] = (L[i] - conj(L[j])) * R[i] / else return {c, d};
29

(2.0 * n) / 1i; }
}
fft(outl), fft(outs);
forn(i,sz(res)) { 6.8 Matrix Exponentiation
ll av = ll(real(outl[i])+.5), cv = ll(
imag(outs[i])+.5); struct matrix{ // define N
ll bv = ll(imag(outl[i])+.5) + ll(real( int r, c, m[N][N];
outs[i])+.5); matrix(int r, int c):r(r),c(c){
res[i] = ((av % M * cut + bv) % M * cut + memset(m, 0, sizeof m);
cv) % M; }
} matrix operator *(const matrix &b){
return res; matrix c = matrix(this->r, b.c);
} forn(i,this->r){
forn(k,b.r){
if(!m[i][k]) continue;
6.6 FHT forn(j,b.c){
c.m[i][j] += m[i][k]*b.m[k][j];
}
ll c1[MAXN+9],c2[MAXN+9]; // MAXN must be power of 2 !! }
void fht(ll* p, int n, bool inv){ }
for(int l=1;2*l<=n;l*=2)for(int i=0;i<n;i+=2*l) return c;
forn(j,l){ }
ll u=p[i+j],v=p[i+l+j]; };

6
if(!inv)p[i+j]=u+v,p[i+l+j]=u-v; // XOR matrix pow(matrix &b, ll e){
else p[i+j]=(u+v)/2,p[i+l+j]=(u-v)/2; matrix c = matrix(b.r, b.c);

MATH
//if(!inv)p[i+j]=v,p[i+l+j]=u+v; // AND forn(i,b.r) c.m[i][i] = 1;
//else p[i+j]=-u+v,p[i+l+j]=u; while(e){
//if(!inv)p[i+j]=u+v,p[i+l+j]=u; // OR if(e&1LL) c = c*b;
6.9
b = b*b , e/=2; x = 1, y = 0;
} ll x1 = 0, y1 = 1, a1 = a, b1 = b;
return c; ll q;

Binary Exponentiation
} while (b1) {
q = a1 / b1;
tie(x, x1) = make_tuple(x1, x - q * x1);
6.9 Binary Exponentiation tie(y, y1) = make_tuple(y1, y - q * y1);
tie(a1, b1) = make_tuple(b1, a1 - q * b1);
}
int binpow(int b, int e) { return a1;
int ans = 1; }
for (; e; b = 1LL*b*b%mod, e /= 2)
if (e&1) ans = 1LL*ans*b%mod; bool find_any_solution(ll a, ll b, ll c, ll &x0, ll &y0,
return ans; ll &g) {
} g = gcde(abs(a), abs(b), x0, y0);
if (c % g) return false;
x0 *= c / g;
6.10 Euler’s Totient Function y0 *= c / g;
if (a < 0) x0 = -x0;
int phi(int n) { // O(sqrt(n)) if (b < 0) y0 = -y0;
if(n==1) return 0; return true;
int ans = n; }
for (int i = 2; 1ll*i*i <= n; i++) {
if(n % i == 0) {
while(n % i == 0) n /= i; 6.12 Inversa modular
ans -= ans / i;
} // O(mod)
30

} const int mod;


if(n > 1) ans -= ans / n; int inv[mod];
return ans; void precalc(){
} inv[1] = 1;
////////////////// fore(i,2,mod-1) inv[i] = (mod - (mod/i) * inv[mod%i] %
vi phi_(int n) { // O(n loglogn) mod) % mod;
vi phi(n + 1); }
phi[0] = 0; /////////////////////////////////////
for1(i,n) phi[i] = i; ll inverse(ll a, ll m){
fore(i,2,n){ ll x, y;
if(phi[i] != i) continue; ll g = gcde(a, m, x, y);
for (int j = i; j <= n; j += i) if (g != 1) {
phi[j] -= phi[j] / i; cout << "No solution!";
} return -1;
} }else{
////////// with linear sieve when i is not a prime number x = (x % m + m) % m;
if (lp[i] == lp[i / lp[i]]) return x;
phi[i] = phi[i / lp[i]] * lp[i]; }
else }
phi[i] = phi[i / lp[i]] * (lp[i] - 1);
6.13 Legendre’s Formula

6
6.11 Extended Euclidean (Diophantic) // Complexity O(log_k (n))

MATH
// If k is prime
// a*x+b*y = g int fact_pow (int n, int k) {
ll gcde(ll a, ll b, ll& x, ll& y) { int x = 0;
6.14
while(n) { b = mulmod(b,b,m);
n /= k; x += n; e = e/2;
} }

Mobious
return x; return r;
} }
// If k is composite k = k1ˆp1 * k2ˆp2 * ... * kmˆpm
// min 1..m ai/ pi where ai is fact_pow(n, ki) bool is_prime(ll n, int a, ll s, ll d){
if(n==a) return true;
ll x=binpow(a,d,n);
if(x==1 || x+1==n)return true;
6.14 Mobious forn(k,s-1){
x=mulmod(x,x,n);
int mu[nax], f[nax], h[nax]; if(x==1) return false;
void pre(){ if(x+1==n) return true;
mu[0] = 0; mu[1] = 1; }
for(int i = 1; i<nax; ++i){ return false;
if(mu[i]==0) continue; }
for(int j= i+i; j<nax; j+=i){ int ar[]={2,3,5,7,11,13,17,19,23,29,31,37};
mu[j] -= mu[i]; bool rabin(ll n){ // true iff n is prime
} if(n==2) return true;
} if(n<2 || n%2==0) return false;
for(int i = 1; i < nax; ++i){ ll s=0,d=n-1;
for(int j = i; j < nax; j += i){ while(d%2==0)++s,d/=2;
f[j] += h[i]*mu[j/i]; forn(i,12) if(!is_prime(n,ar[i],s,d)) return
} false;
} return true;
} }
31

//////// ///////////////////////////////////////
void pre(){
mu[0] = 0; mu[1] = 1; bool isPrime(ll n) {
fore(i,2,N){ if (n < 2 || n % 6 % 4 != 1) return (n | 1) == 3;
if (lp[i] == 0) { ll A[] = {2, 325, 9375, 28178, 450775, 9780504,
lp[i] = i; mu[i] = -1; 1795265022};
pr.pb(i); ll s=0,d=n-1;
} while(d%2==0)++s,d/=2;
for (int j=0, mult= i*pr[j]; j<sz(pr) && pr[j]<=lp[i] for (ll a : A) { // ˆ count trailing zeroes
&& mult<=N; ++j, mult= i*pr[j]){ ll p = binpow(a%n, d, n), i = s;
if(i%pr[j]==0) mu[mult] = 0; while (p != 1 && p != n - 1 && a % n && i
else mu[mult] = mu[i]*mu[pr[j]]; --)
lp[mult] = pr[j]; p = mulmod(p, p, n);
} if (p != n-1 && i != s) return 0;
} }
} return 1;
}
6.15 Miller Rabin Test
6.16 Pollard Rho
ll mulmod(ll a, ll b, ll m) {
ll r=a*b-(ll)((long double)a*b/m+.5)*m; ll rho(ll n){
return r<0?r+m:r; if(!(n&1))return 2;

6
} ll x=2,y=2,d=1;
ll binpow(ll b, ll e, ll m){ ll c=rand()%n+1;

MATH
ll r = 1; while(d==1){
while(e){ x=(mulmod(x,x,n)+c)%n;
if(e&1) r = mulmod(r, b,m); y=(mulmod(y,y,n)+c)%n;
6.17
y=(mulmod(y,y,n)+c)%n; *(m2/__gcd(m1,m2));
if(x>=y)d=__gcd(x-y,n); x1=MOD((__int128_t)m1*k+x1,l); m1=l;
else d=__gcd(y-x,n); }

Chinese Remainder Theorem


} return sol(make_tuple(1,x1,m1));
return d==n?rho(n):d; } //cond[i]={ai,bi,mi} ai*xi=bi (mi); assumes lcm fits in
} ll
void fact(ll n, map<ll,int>& f){ //O (lg n)ˆ3
if(n==1)return;
if(rabin(n)){f[n]++;return;}
ll q=rho(n);fact(q,f);fact(n/q,f); 6.18 Simplex
}
#include "../c++/template.cpp"
vi X, Y;
6.17 Chinese Remainder Theorem ld Z;
int n, m;
pll extendedEuclid(ll a, ll b){ // a * x + b * y = __gcd( vd b, c; // Cantidades, costos
a,b) vector<vd> a; // Variables, restricciones
ll x,y; void pivot(int x, int y){
if (b==0) return {1,0}; swap(X[y], Y[x]);
auto p=extendedEuclid(b,a%b); b[x] /= a[x][y];
x=p.se; forn(j, m) if(j != y) a[x][j] /= a[x][y];
y=p.fi-(a/b)*x; a[x][y] = 1 / a[x][y];
if(a*x+b*y==-__gcd(a,b)) x=-x, y=-y; forn(i, n) if(i != x && abs(a[i][y]) > eps){
return {x,y}; b[i] -= a[i][y] * b[x];
} forn(j, m) if(j != y) a[i][j] -= a[i][y] * a[x][j];
pair<pll,pll> diophantine(ll a, ll b, ll r) { a[i][y] = -a[i][y] * a[x][y];
//a*x+b*y=r where r is multiple of __gcd(a,b); }
32

ll d=__gcd(a,b); Z += c[y] * b[x];


a/=d; b/=d; r/=d; forn(j, m) if(j != y) c[j] -= c[y] * a[x][j];
auto p = extendedEuclid(a,b); c[y] = -c[y] * a[x][y];
p.fi*=r; p.se*=r; }
// assert(a*p.fi+b*p.se==r); pair<ld, vd> simplex(){ // maximizar Z = c * x dado ax
return {p,{-b,a}}; // solutions: p+t*ans.se <= b, x_i >= 0
} X.resize(m), iota(all(X), 0);
ll inv(ll a, ll m) { Y.resize(n), iota(all(Y), m);
assert(__gcd(a,m)==1); while(1){
ll x = diophantine(a,m,1).fi.fi; int x = min_element(all(b)) - b.begin(), y = -1;
return ((x%m)+m)%m; if(b[x] > -eps) break;
}
#define MOD(a,m) (((a)%m+m)%m) forn(j, m) if(a[x][j] < -eps){ y = j; break; }
pll sol(tuple<ll,ll,ll> c){ //requires inv, diophantine if(y == -1) return {-1, {}}; // no solution to Ax<=b
ll a=get<0>(c), x1=get<1>(c), m=get<2>(c), d=__gcd(a,m) pivot(x, y);
; }
if(d==1) return pll(MOD(x1*inv(a,m),m), m); while(1){
else return x1%d ? pll({-1LL,-1LL}) : sol(make_tuple(a/ int x = -1, y = max_element(all(c)) - c.begin();
d,x1/d,m/d)); if(c[y] < eps) break;
} ld mn = inf;
pair<ll,ll> crt(vector< tuple<ll,ll,ll> > &cond) { // forn(i, n) if(a[i][y] > eps && b[i] / a[i][y] < mn)
returns: (sol, lcm) mn = b[i] / a[i][y], x = i;
ll x1=0,m1=1,x2,m2; if(x == -1) return {inf, {}}; // cˆT x is unbounded

6
for(auto &t: cond){ pivot(x, y);
tie(x2,m2)=sol(t); }

MATH
if((x1-x2)%__gcd(m1,m2))return {-1,-1}; vd ans(m);
if(m1==m2)continue; forn(i, n) if(Y[i] < m) ans[Y[i]] = b[i];
ll k=diophantine(m2,-m1,x1-x2).fi.se,l=m1 return {Z, ans};
6.19
} if(abs(a[sel][col]) <= eps) continue;
fore(i,col,m) swap (a[sel][i], a[row][i]);

Gauss Jordan
where[col] = row;
6.19 Gauss Jordan
forn(i,n){
int gauss(vector<vector<double>> &a, vector<double> &ans) if (i != row) {
{ int c = 1LL*a[i][col] * inv(a[row][col])%mod;
int n = sz(a), m = sz(a[0]) - 1; for (int j=col; j<=m; ++j) a[i][j] = (mod + a[i][
vi where(m, -1); j] - (1LL*a[row][j] * c)%mod)%mod;
for(int col=0, row=0; col<m && row<n; ++col) { }
int sel = row; }
fore(i,row,n-1) ++row;
}
if(abs(a[i][col]) > abs(a[sel][col])) sel = i;
if(abs(a[sel][col]) < eps) continue; ans.assign(m, 0);
forn(i,m){
fore(i,col,m) swap (a[sel][i], a[row][i]); if(where[i] != -1) ans[i] = 1LL*a[where[i]][m] * inv(
where[col] = row; a[where[i]][i])%mod;
forn(i,n){ }
if (i != row) { forn(i,n){
double c = a[i][col] / a[row][col]; ll sum = 0;
for (int j=col; j<=m; ++j) a[i][j] -= a[row][j] * forn(j,m) sum = (sum + 1LL*ans[j] * a[i][j])%mod;
c; if(abs(sum - a[i][m]) > eps) return 0;
} }
}
++row; forn(i,m) if(where[i] == -1) return 1e9; /// infinitas
} soluciones
return 1;
33

ans.assign(m, 0); }
forn(i,m){
if(where[i] != -1) ans[i] = a[where[i]][m] / a[where[
i]][i];
} 6.21 Berlekamp Massey
forn(i,n){
double sum = 0; // taken from https://codeforces.com/blog/entry/61306
forn(j,m) sum += ans[j] * a[i][j]; struct ber_ma{
if(abs(sum - a[i][m]) > eps) return 0; vi BM(vi &x){
} vi ls,cur; int lf,ld;
forn(i,m) if(where[i] == -1) return 1e9; /// infinitas forn(i,sz(x)){
soluciones ll t=0;
return 1; forn(j,sz(cur)) t=(t+x[i-j-1]*(ll
} )cur[j])%mod;
if((t-x[i])%mod==0) continue;
if(!sz(cur)){
cur.resize(i+1);
6.20 Gauss Jordan Modular lf=i; ld=(t-x[i])%mod;
continue;
const int eps = 0, mod = 1e9+7; }
ll k=-(x[i]-t)*inv(ld,mod);
int gauss(vector<vi> &a, vi &ans) { vi c(i-lf-1); c.pb(k);
int n = sz(a), m = sz(a[0]) - 1; forn(j,sz(ls)) c.pb(-ls[j]*k%mod)

6
vi where(m, -1); ;
for(int col=0, row=0; col<m && row<n; ++col) { if(sz(c)<sz(cur)) c.resize(sz(cur

MATH
int sel = row; ));
fore(i,row,n-1) forn(j,sz(cur)) c[j]=(c[j]+cur[j
if(abs(a[i][col]) > abs(a[sel][col])) sel = i; ])%mod;
6.22
if(i-lf+sz(ls)>=sz(cur)) ls=cur, const int N = 1e6;
lf=i,ld=(t-x[i])%mod; mint f[N], fr[N];
cur=c; void initC(){

Lagrange Interpolation
} if(f[0] == 1) return; // Already precalculated
forn(i,sz(cur)) cur[i]=(cur[i]%mod+mod)% f[0] = 1;
mod; for1(i, N-1) f[i] = f[i-1] * i;
return cur; fr[N-1] = bpow(f[N-1], mod-2);
} fored(i, 1, N-1) fr[i-1] = fr[i] * i;
int m; //length of recurrence }
//a: first terms // mint C(int n, int k) { return k<0 || k>n ? 0 : f[n] *
//h: relation fr[k] * fr[n-k]; }
vector<ll> a, h, t_, s, t; struct LagrangePol {
//calculate p*q mod f int n;
inline vector<ll> mull(vector<ll> p, vector<ll> q vector<mint> y, den, l, r;
){ LagrangePol(vector<mint> f): n(sz(f)), y(f), den(n), l(
forn(i,2*m) t_[i]=0; n), r(n){// f[i] := f(i)
forn(i,m) if(p[i]) // Calcula interpol. pol P in O(n) := deg(P) = sz(v)
forn(j,m) -1
t_[i+j]=(t_[i+j]+p[i]*q[j initC();
])%mod; forn(i, n) {
for(int i=2*m-1;i>=m;--i) if(t_[i]) den[i] = fr[n-1-i] * fr[i];
forn(j,m) if((n-1-i) & 1) den[i] = -den[i];
t_[i-j-1]=(t_[i-j-1]+t_[i }
]*h[j])%mod; }
forn(i,m) p[i]=t_[i]; mint eval(mint x){ // Evaluate LagrangePoly P(x) in O(n
return p; )
} l[0] = r[n-1] = 1;
34

inline ll calc(ll k){ for1(i, n-1) l[i] = l[i-1] * (x - i + 1);


if(k < sz(a)) return a[k]; fored(i, 0, n-2) r[i] = r[i+1] * (x - i - 1);
forn(i,m) s[i]=t[i]=0; mint ans = 0;
s[0]=1; forn(i, n) ans += l[i] * r[i] * y[i] * den[i];
if(m!=1) t[1]=1; return ans;
else t[0]=h[0]; }
};
while(k){
if(k&1LL) s = mull(s,t);
t = mull(t,t); k/=2;
} 6.23 Discrete Log
ll su=0;
forn(i,m) su=(su+s[i]*a[i])%mod;
return (su%mod+mod)%mod; // Returns minimum x for which a ˆ x % m = b % m.
} int solve(int a, int b, int m) {
ber_ma(vi &x){ a %= m, b %= m;
vi v = BM(x); m=sz(v); int k = 1, add = 0, g;
h.resize(m), a.resize(m), s.resize(m); while ((g = gcd(a, m)) > 1) {
t.resize(m), t_.resize(2*m); if (b == k)
forn(i,m) h[i]=v[i],a[i]=x[i]; return add;
} if (b % g)
}; return -1;
b /= g, m /= g, ++add;
k = (k * 1ll * a / g) % m;

6
}
6.22 Lagrange Interpolation

MATH
int n = sqrt(m) + 1;
int an = 1;
#include "mint.cpp" for (int i = 0; i < n; ++i)
6.24
an = (an * 1ll * a) % m; b *= b;
}while(e >>= 1);
unordered_map<int, int> vals; return a;

Fractions
for (int q = 0, cur = b; q <= n; ++q) { }
vals[cur] = q; struct mint {
cur = (cur * 1ll * a) % m; int x;
} mint(): x(0){}
for (int p = 1, cur = k; p <= n; ++p) { mint(ll v) : x((v % mod + mod) % mod) {} // be careful
cur = (cur * 1ll * an) % m; of negative numbers!
if (vals.count(cur)) { // Helpers to shorten code
int ans = n * p - vals[cur] + add; #define add(a, b) a + b >= mod ? a + b - mod : a + b
return ans; #define sub(a, b) a < b ? a + mod - b : a - b
} #define yo *this
} #define cmint const mint&
return -1;
} mint &operator += (cmint o) { return x = add(x, o.x),
yo; }
mint &operator -= (cmint o) { return x = sub(x, o.x),
yo; }
6.24 Fractions mint &operator *= (cmint o) { return x = ll(x) * o.x %
mod, yo; }
struct frac{ mint &operator /= (cmint o) { return yo *= bpow(o, mod
ll num, den; -2); }
frac(){}
frac(ll num, ll den):num(num), den(den){ mint operator + (cmint b) const { return mint(yo) += b;
if(!num) den = 1; }
if(num > 0 && den < 0) num = -num, den = -den; mint operator - (cmint b) const { return mint(yo) -= b;
}
35

simplify(); mint operator


} * (cmint b) const { return mint(yo) *= b;
void simplify(){ }
ll g = __gcd(abs(num), abs(den)); mint operator / (cmint b) const { return mint(yo) /= b;
}
if(g) num /= g, den /= g;
} mint operator - () const { return mint() - mint(yo); }
frac operator+(const frac& b){ return {num*b.den + b. bool operator == (cmint b) const { return x == b.x; }
num*den, den*b.den};} bool operator != (cmint b) const { return x != b.x; }
frac operator-(const frac& b){ return {num*b.den - b.
num*den, den*b.den};} friend ostream& operator << (ostream &os, cmint p) {
frac operator*(const frac& b){ return {num*b.num, den*b return os << p.x; }
.den};} friend istream& operator >> (istream &is, mint &p) {
frac operator/(const frac& b){ return {num*b.den, den*b return is >> p.x; }

7
.num};} };

DYNAMIC PROGRAMMING
bool operator<(const frac& b)const{ return num*b.den <
den*b.num; }
};
7 Dynamic Programming
6.25 Modular Int 7.1 Edit Distance
typedef long long ll; // O(m*n) donde cada uno es el tamano de cada string
const int mod = 1e9 + 7; int editDist(string &s1, string &s2){
template <class T> int m = sz(s1), n = sz(s2);
T bpow(T b, int e) { int dp[m+1][n+1];
T a(1); forn(i,m+1)
do{ forn(j,n+1){
if(e & 1) a *= b; if (i==0) dp[i][j] = j;
7.2
else if (j==0) dp[i][j] = i;
else if (s1[i-1] == s2[j-1]) dp[i][j] = dp[i-1][j 7.4 Trick to merge intervals
-1];

Longest common subsequence


else dp[i][j] = 1 + min({dp[i][j-1], // Insert
dp[i-1][j], // Remove // Option 1
dp[i-1][j-1]}); // Replace for(int len= 0; len<n; ++len){
} for(int l= 0; l<n-len; ++l){
return dp[m][n]; int r= l+len;
} dp[l][r]= max(dp[l+1][r], dp[l][r-1]);
}
}
// Option 2
7.2 Longest common subsequence for(int l= n-1; l>=0; --l){
for(int r= l; r<n ; ++r){
dp[l][r]= max(dp[l+1][r], dp[l][r-1]);
const int nax = 1005; }
int dp[nax][nax]; }
int lcs(const string &s, const string &t){
int n = sz(s), m = sz(t);
forn(j,m+1) dp[0][j] = 0; 7.5 Trick Sets DP
forn(i,n+1) dp[i][0] = 0;
for1(i,n){ // Complexity O(N*2ˆN)
for1(j,m){ const int N;
dp[i][j] = max(dp[i-1][j], dp[i][j-1]); int dp[1<<N][N+1];
if (s[i-1] == t[j-1]){ int F[1<<N];
dp[i][j] = max(dp[i][j], dp[i-1][j-1] + 1); int A[1<<N];
} // ith bit is ON S(mask, i) = S(mask, i-1)
36

} // ith bit is OFF S(mask,i) = S(mask, i-1) + S(maskˆ(1<<i


} ), i-1)
return dp[n][m];
} //iterative version
forn(mask,(1<<N)){
dp[mask][0] = A[mask]; //handle base case
separately (leaf states)
7.3 Longest increasing subsequence forn(i,N){
if(mask & (1<<i))
dp[mask][i+1] = dp[mask][i] + dp[
// Complejidad n log n maskˆ(1<<i)][i];
int lis(const vi &a) { else
dp[mask][i+1] = dp[mask][i];

7
int n = a.size();
vi d(n+1, inf); }

DYNAMIC PROGRAMMING
d[0] = -inf; F[mask] = dp[mask][N];
}
for (int i = 0; i < n; i++) { //memory optimized, super easy to code.
int j = upper_bound(d.begin(), d.end(), a[i]) - d. forn(i,(1<<N)) F[i] = A[i];
begin(); forn(i,N)
if (d[j-1] < a[i] && a[i] < d[j]) d[j] = a[i]; forn(mask,(1<<N)){
} if(mask & (1<<i)) F[mask] += F[maskˆ(1<<i)];
}
int ans = 0;
for (int i = 0; i <= n; i++) {
if (d[i] < inf) ans = i;
} 7.6 Divide and Conquer
return ans;
} const ll inf = 1e18;
const int nax = 1e3+20, kax = 20;
7.7
ll C[nax][nax], dp[kax][nax];
int n; 7.8 Convex Hull Trick

Knuth’s Optimization
void compute(int k, int l, int r, int optl, int optr){ struct line {
if(l>r) return ; ll m, b;
int mid= (l+r)/2, opt; ll eval(ll x) { return m * x + b; }
pll best= {inf,-1}; ld inter(line &l) { return (ld) (b - l.b) / (l.m - m);
for(int i= max(mid,optl); i<= optr ; ++i ){ }
best = min(best, {dp[k-1][i+1] + C[mid][i] ,i} ); };
}
tie(dp[k][mid], opt) = best; struct cht {
compute(k,l, mid-1, optl, opt); vector<line> lines;
compute(k,mid+1, r, opt, optr); vector<ld> inter;
} int n;
inline bool ok(line &a, line &b, line &c) {
inside main(){ return a.inter(c) > a.inter(b);
fore(k,1,K) // definir el caso base k = 0. }
compute(k,0,n-1,0,n-1); void add(line &l) { /// m1 < m2 < m3 ...
} n = sz(lines);
if(n && lines.back().m == l.m && lines.back().b >= l.
b) return;
if(n == 1 && lines.back().m == l.m && lines.back().b
< l.b) lines.pop_back(), n--;
7.7 Knuth’s Optimization while(n >= 2 && !ok(lines[n-2], lines[n-1], l)) {
--n;
lines.pop_back(); inter.pop_back();
const int nax = 1e3+20; }
37

const ll inf = LONG_LONG_MAX; lines.pb(l); n++;


ll dp[nax][nax]; if(n >= 2) inter.pb(lines[n-2].inter(lines[n-1]));
int k[nax][nax]; }
int C[nax][nax]; // puede depender de k ll get_max(ld x) {
if(sz(lines) == 0) return LLONG_MIN;
int main(){ if(sz(lines) == 1) return lines[0].eval(x);
for(int len=2; len<n; ++len){ int pos = lower_bound(all(inter), x) - inter.begin();
for(int l=0; l< n-len; ++l){ return lines[pos].eval(x);
int r= l+len; }
ll &ans= dp[l][r]; };
if(len== 2){
k[l][r]= l+1;

7
ans= C[l][r];
continue; 7.9 CH Trick Dynamic

DYNAMIC PROGRAMMING
}
ans= inf; typedef ll T;
for(int i= k[l][r-1]; i<= k[l+1][r]; ++i ){ const T is_query = -(1LL << 62);
if(ans> dp[l][i]+ dp[i][r]){ struct line {
ans= dp[l][i] + dp[i][r]; T m, b;
k[l][r]= i; mutable multiset<line>::iterator it, end;
} const line *succ(multiset<line>::iterator it)
} const {
ans+= C[l][r]; return (++it == end ? nullptr : &*it);
} }
} bool operator < (const line &l) const {
cout<< dp[0][n-1]<<el; if(l.b != is_query) return m < l.m;
} auto s = succ(it);
if(!s) return 0;
return b - s->b < ld(s->m - m) * l.m; bool operator==(pt p){ return abs(x - p.x) <= eps &&
} abs(y - p.y) <= eps; }
}; bool operator<(pt p)const{ // for sort, convex
struct CHT : public multiset<line> { hull/set/map
iterator nex(iterator y){ return ++y; } return x < p.x - eps || (abs(x - p.x) <=
iterator pre(iterator y){ return --y; } eps && y < p.y - eps); }
bool bad(iterator y) { bool operator!=(pt p){ return !operator==(p); }
auto z = nex(y); // -------------- NORMS -------------- //
if(y == begin()) { ld norm2(){ return *this**this; }
if(z == end()) return 0; ld norm(){ return sqrt(norm2()); }
return y->m == z->m && y->b <= z pt unit(){ return *this/norm(); }
->b; // ------------ SIDE, LEFT------------ //
} ld side(pt p, pt q){ return (q-p) % (*this-p); }// C is
auto x = pre(y); : >0 L, ==0 on AB, <0 R
if(z == end()) return y->m == x->m && y-> bool left(pt p, pt q){ // Left of directed line
b == x->b; PQ? (eps == 0 if integer)
return ld(x->b - y->b)*(z->m - y->m) >= return side(p, q) > eps; } // (change to
ld(y->b - z->b)*(y->m - x->m); >= -eps to accept collinear)
} // -------------- ANGLES -------------- //
void add(T m, T b) { ld angle(){ return atan2(y, x); } // Angle from origin,
auto y = insert(line{m, b}); in [-pi, pi]
y->it = y, y->end = end(); ld min_angle(pt p){ return acos(*this*p / (norm()*p.
if(bad(y)){ erase(y); return; } norm())); } // In [0, pi]
while(nex(y) != end() && bad(nex(y))) ld angle(pt a, pt b, bool CW){ // Angle< AB(*this) > in
erase(nex(y)); direction CW
while(y != begin() && bad(pre(y))) erase( ld ma = (a - b).min_angle(*this - b);
pre(y)); return side(a, b) * (CW ? -1 : 1) <= 0 ? ma : 2*pi -
38

} ma; }
T eval(T x) { /// max bool in_angle(pt a, pt b, pt c, bool CW=1){ // Is pt
line l = *lower_bound(line{x, is_query}); inside infinite angle ABC
return l.m*x + l.b; return angle(a, b, CW) <= c.angle(a, b, CW); } //
} From AB to AC in CW direction
}; // -------------- ROTATIONS -------------- //
pt rot(pt p){ return pt(*this % p,*this * p); }//
use ccw90(1,0), cw90(-1,0)
pt rot(ld ang){ return rot(pt(sin(ang), cos(ang))
8 Geometry ); } // CCW, ang (radians)
pt rot_around(ld ang, pt p){ return p + (*this -
p).rot(ang); }
8.1 Point pt perp(){ return rot(pt(1, 0)); }
// -------------- SEGMENTS -------------- //
struct pt{ bool in_disk(pt p, pt q){ return (p - *this) * (q - *
ld x, y; this) <= 0; }
pt(){} bool on_segment(pt p, pt q){ return side(p, q) == 0 &&
pt(ld x, ld y): x(x), y(y){} in_disk(p, q); }
pt(ld ang): x(cos(ang)), y(sin(ang)){} // Polar };
unit point: ang(randians) int sgn(ld x){

8
// ------- BASIC OPERATORS ------- // if(x < 0) return -1;
pt operator+(pt p){ return pt(x+p.x, y+p.y); } return x == 0 ? 0 : 1;

GEOMETRY
pt operator-(pt p){ return pt(x-p.x, y-p.y); } }
pt operator*(ld t){ return pt(x*t, y*t); } void segment_intersection(pt a, pt b, pt c, pt d, vector<
pt operator/(ld t){ return pt(x/t, y/t); } pt>& out){ // AB y CD
ld operator*(pt p){ return x*p.x + y*p.y; } ld sa = a.side(c, d), sb = b.side(c, d);
ld operator%(pt p){ return x*p.y - y*p.x; } ld sc = c.side(a, b), sd = d.side(a, b); //
// ------- COMPARISON OPERATORS ------- // proper cut
8.2
if(sgn(sa)*sgn(sb) < 0 && sgn(sc)*sgn(sd) < 0) out.pb(( pt operator-(pt p){return pt(x - p.x, y - p.y);}
a*sb - b*sa) / (sb-sa)); ld operator%(pt p){return x * p.y - y * p.x;}
for(pt p : {c, d}) if(p.on_segment(a, b)) out.pb(p); ld side(pt p, pt q){return (q - p) % (*this - p);}

Line
for(pt p : {a, b}) if(p.on_segment(c, d)) out.pb(p); };
} // CCW order, excludes collinear points
// Change .side(r[sz(r)-2], p[i]) > 0 to include
collinear
8.2 Line vector<pt> chull(vector<pt>& p){
if(sz(p) < 3) return p;
vector<pt> r;
// Add point.cpp Basic operators sort(all(p)); // first x, then y
struct line{ forn(i, sz(p)){ // lower hull
pt v; ld c; while(sz(r) > 1 && r.back().side(r[sz(r)-2], p[i]) >=
line(){} 0) r.pop_back();
line(pt p, pt q): v(q - p), c(v % p){} r.pb(p[i]);
line(pt v, ld c): v(v), c(c){} }
line(ld a, ld b, ld c): v({b, -a}), c(c){} r.pop_back();
bool operator<(line l){ return v % l.v > 0; } int k = sz(r);
bool operator/(line l){ return v % l.v == 0; } // abs() fored(i, 0, sz(p)-1){ // upper hull
<= eps while(sz(r) > k+1 && r.back().side(r[sz(r)-2], p[i])
pt operatorˆ(line l){ // LINE - LINE Intersection >= 0) r.pop_back();
if(*this / l) return pt(inf, inf); // PARALLEL r.pb(p[i]);
return (l.v*c - v*l.c) / (v % l.v); }
} r.pop_back();
ld side(pt p){ return v % p - c; } return r;
bool has(pt p){ return v % p == c; } }
pt proj(pt p) { return p - v.perp() * side(p) / v.norm2
(); }
39

pt refl(pt p) { return proj(p) * 2 - p; } 8.4 Polygon


bool cmp_proj(pt p, pt q){ return v * p < v * q; }
ld dist(pt p){ return abs(side(p)) / v.norm(); }
ld dist2(pt p){ return side(p) * side(p) / double(v. #include "line.cpp"
norm2()); } #include "circle.cpp"
#include "convex_hull.cpp"
bool operator==(line l){ return *this / l && c == l.c; int sgn(double x){return x<-eps?-1:x>eps;}
} struct poly {
ld angle(line l){ return v.min_angle(l.v); } // int n, normal = -1; vector<pt> p;
/angle bet. 2 lines poly(){}
line perp_at(pt p) { return {p, p + v.perp() }; } poly(const vector<pt>& p): p(p), n(sz(p)){}
line translate(pt t) { return {v, c + (v % t)}; }
line shift_left(ld dist){ return {v, c + dist * v.norm double area(){
()}; } double r=0.;
}; forn(i, n) r += p[i] % p[(i+1)%n];
return abs(r)/2; // negative if CW,
positive if CCW
}
8.3 Convex Hull
bool isConvex() {

8
struct pt{ bool pos=false, neg=false;
ld x, y; forn(i, n) {

GEOMETRY
pt(){} int s = p[(i+2)%n].side(p[i], p[(i+1)%n]);
pt(ld x, ld y): x(x), y(y){} pos |= s > 0;
bool operator<(pt p)const{ // for sort, convex hull/set neg |= s < 0;
/map }
return x < p.x - eps || (abs(x - p.x) <= return !(pos && neg);
eps && y < p.y - eps); } }
8.4
}
pt centroid(){ // (barycenter) return !q.left(p[l], p[l+1]);
pt r(0,0); double t=0; ///REVISAR }

Polygon
forn(i,n){ // ------------ FARTHEST------------ //
r = r+(p[i]+p[(i+1)%n])*(p[i]%p[( pt farthest(pt v){ /// O(log(n)) only CONVEX
i+1)%n]); if(n < 10){
t += p[i]%p[(i+1)%n]; int k=0;
} for1(i,n-1) if(v*(p[i]-p[k]) >
return r/t/3; eps) k=i;
} return p[k];
}
bool has(pt q){ /// O(n) if(n == sz(p)) p.pb(p[0]);
forn(i, n) if(q.on_segment(p[i], p[(i+1) pt a = p[1]-p[0];
% n])) return true; int s=0, e=n, ua=v*a>eps;
int cnt = 0; if(!ua && v*(p[n-1]-p[0]) <= eps) return
forn(i, n){ p[0];
int j = (i+1)%n; while(1){
int k = sgn((q - p[j]) % (p[i] - int m = (s+e)/2; pt c=p[m+1]-p[m
p[j])); ];
int u = sgn(p[i].y - q.y), v = int uc = v*c> eps;
sgn(p[j].y - q.y); if(!uc && v*(p[m-1]-p[m]) <= eps)
if(k > 0 && u < 0 && v >= 0) ++ return p[m];
cnt; if(ua && (!uc||v*(p[s]-p[m]) >
if(k < 0 && v < 0 && u >= 0) -- eps))e=m;
cnt;
} else if(ua || uc || v*(p[s]-p[m])
return cnt!=0; >= -eps) s=m, a=c, ua=uc;
} else e=m;
40

// ------------ HAS_LOG ------------ // assert(e>s+1);


void remove_col(){ // helper }
vector<pt> s; }
forn(i, n) if(!p[i].on_segment(p[(i-1+n) % n], p[(i poly cut(line l){ // cut CONVEX polygon by line
+1) % n])) s.pb(p[i]); l
p.swap(s); n = sz(p); vector<pt> q; // returns part at left of
} l.pq
void normalize(){ // helper forn(i, n) {
remove_col(); int d0 = sgn(l.side(p[i])), d1 =
if(p[2].left(p[0], p[1])) reverse(all(p)); sgn(l.side(p[(i+1) % n]));
int pi = min_element(all(p)) - p.begin(); if(d0 >= 0) q.pb(p[i]);
vector<pt> s(n); line m(p[i], p[(i+1) % n]);
forn(i, n) s[i] = p[(pi+i) % n]; if(d0*d1 < 0 && !(l / m)) q.pb(l
p.swap(s); n = sz(p); ˆ m);
} }
bool has_log(pt q){ /// O(log(n)) only CONVEX. return poly(q);
if(normal == -1) normal = 1, normalize(); }
if(q.left(p[0], p[1]) || q.left(p[n-1], p[0])) return ld intercircle(circle c){ /// area of
false; intersection with circle
int l = 1, r = n-1; // returns true if point on ld r = 0.;

8
boundary forn(i,n){

GEOMETRY
while(l+1 < r){ // (change sign of EPS in int j = (i+1)%n; ld w = c.
left intertriangle(p[i], p[j]);
int m = (l+r) / 2; // to return false in if((p[j]-c.o)%(p[i]-c.o) > 0) r+=
such case) w;
if(!q.left(p[0], p[m])) l = m; else r-=w;
else r = m; }
8.5
return abs(r); s.pb(o + v*x - v.rot(pt(1, 0))*y);
} if(y > eps) s.pb(o + v*x + v.rot(pt(1, 0)
)*y);

Circle
ld callipers(){ // square distance: pair of most return s;
distant points }
ld r=0; // prereq: convex, ccw, NO vector<pt> operatorˆ(line l){
COLLINEAR POINTS vector<pt> s;
for(int i=0,j=n<2?0:1; i<j; ++i){ pt p = l.proj(o);
for(;;j=(j+1)%n){ ld d = (p-o).norm();
r = max(r,(p[i]-p[j]). if(d - eps > r) return s;
norm2()); if(abs(d-r) <= eps){ s.pb(p); return s; }
if((p[(i+1)%n]-p[i])%(p[( d=sqrt(r*r - d*d);
j+1)%n]-p[j]) <= eps) s.pb(p + l.v.unit() * d);
break; s.pb(p - l.v.unit() * d);
} return s;
} }
return r; vector<pt> tang(pt p){
} ld d = sqrt((p-o).norm2()-r*r);
}; return *thisˆcircle(p,d);
// / max_dist between 2 points (pa, pb) of 2 Convex }
polygons (a, b) bool in(circle c){ return (o-c.o).norm() + r <=
ld rotating_callipers(vector<pt>& a, vector<pt>& b){ c.r + eps; } // non strict
pair<ll, int> start = {-1, -1}; ld intertriangle(pt a, pt b){ // area of
if(sz(a) == 1) swap(a, b); intersection with oab
forn(i, sz(a)) start = max(start, {(b[0] - a[i]).norm2 if(abs((o-a) % (o-b)) <= eps) return 0.;
(), i}); vector<pt> q = {a}, w = *this ˆ line(a, b
if(sz(b) == 1) return start.fi; );
41

if(sz(w) == 2) for(auto p: w) if((a-p) *


ld r = 0; (b-p)<-eps) q.pb(p);
for(int i = 0, j = start.se; i<sz(b); ++i){ q.pb(b);
for(;; j = (j+1) % sz(a)){ if(sz(q) == 4 && (q[0] - q[1]) * (q[2] -
r = max(r, (b[i] - a[j]).norm2()); q[1]) > eps) swap(q[1], q[2]);
if((b[(i+1) % sz(b)] - b[i]) % (a[(j+1) % sz(a)] - ld s = 0;
a[j]) <= eps) break; forn(i, sz(q)-1){
} if(!has(q[i]) || !has(q[i+1])) s
} += r*r * (q[i] - o).min_angle(
return r; q[i+1] - o) / 2;
} else s += abs((q[i] - o) % (q[i
+1] - o) / 2);
}
8.5 Circle return s;
}
// Add point.cpp and line.cpp Basic operators };
struct circle { vector<ld> intercircles(vector<circle> c){
pt o; ld r; vector<ld> r(sz(c) + 1); // r[k]: area covered by
circle(pt o, ld r):o(o),r(r){} at least k circles
bool has(pt p){ return (o-p).norm() <= r+eps;} forn(i, sz(c)){ // O(nˆ2 log n) (high

8
vector<pt> operatorˆ(circle c){ // ccw constant)
vector<pt> s; int k = 1; pt O = c[i].o;

GEOMETRY
ld d = (o - c.o).norm(); vector<pair<pt, int>> p = {
if(d > r + c.r + eps || d + min(r, c.r) + {c[i].o + pt(1,0) * c[i].r, 0},
eps < max(r, c.r)) return s; {c[i].o - pt(1,0) * c[i].r, 0}};
ld x = (d*d - c.r*c.r + r*r)/(2*d); forn(j, sz(c)) if(j != i){
ld y = sqrt(r*r - x*x); bool b0 = c[i].in(c[j]), b1 = c[j
pt v = (c.o - o) / d;
8.6
].in(c[i]);
if(b0 && (!b1 || i < j)) ++k; 8.7 Halfplane

Radial Order
else if(!b0 && !b1){
auto v = c[i] ˆ c[j];
if(sz(v) == 2){ typedef double ld;
p.pb({v[0], 1}); const ld eps = 1e-7, inf = 1e12;
p.pb({v[1], struct pt { // for 3D add z coordinate
-1}); ld x, y;
if(cmp(v[1] - O, pt(){}
v[0] - O)) ++k pt(ld x, ld y): x(x), y(y){}
; pt operator-(pt p){return pt(x - p.x, y - p.y);}
} pt operator*(ld t){return pt(x * t, y t);}
} *
pt operator/(ld t){return pt(x / t, y / t);}
} // FOR "cmp" see "radial_order.cpp" ld operator%(pt p){return x * p.y - y p.x;}
sort(all(p), [&](auto& a, auto& b){ *
ld operator*(pt p){return x * p.x + y * p.y;}
return cmp(a.fi - O, b.fi - O); }); };
forn(j, sz(p)){
pt p0 = p[j ? j-1 : sz(p)-1].fi, struct halfplane {
p1 = p[j].fi; pt p, v; ld c, angle;
ld a = (p0 - c[i].o).min_angle(p1 halfplane(){}
- c[i].o); halfplane(pt p, pt q): p(p), v(q - p), c(v % p), angle(
r[k] += (p0.x - p1.x)*(p0.y + p1. atan2(v.y, v.x)){}
y)/2 + c[i].r*c[i].r*(a - sin( bool operator<(halfplane b)const{ return angle < b.
a))/2; angle; }
k += p[j].se; bool operator/(halfplane l){ return abs(v % l.v) <= eps
} ; } // 2D
} pt operatorˆ(halfplane l){ return *this / l ? pt(inf,
return r; inf) : (l.v*c - v*l.c) / (v % l.v);}
42

} bool out(pt q){ return v % q < c; } // try < c-eps


};
vector<pt> intersect(vector<halfplane> b){
8.6 Radial Order vector<pt> bx = {{inf, inf}, {-inf, inf}, {-inf, -inf},
{inf, -inf}};
typedef double ld; forn(i, 4) b.pb(halfplane(bx[i], bx[(i+1) % 4]));
struct pt{ sort(all(b));
ld x, y; int n = sz(b), q = 1, h = 0;
pt(){} vector<halfplane> c(sz(b) + 10);
pt(ld x, ld y): x(x), y(y){} forn(i, n){
pt operator-(pt p){ return pt(x-p.x, y-p.y); } while(q < h && b[i].out(c[h] ˆ c[h-1])) --h;
ld operator%(pt p){ return x*p.y - y*p.x; } while(q < h && b[i].out(c[q] ˆ c[q+1])) ++q;
int cuad(){ c[++h] = b[i];
if(x > 0 && y >= 0) return 0; if(q < h && abs(c[h].v % c[h-1].v) < eps){
if(x <= 0 && y > 0) return 1; if(c[h].v * c[h-1].v <= 0) return {};
if(x < 0 && y <= 0) return 2; h--;
if(x >= 0 && y < 0) return 3; if(b[i].out(c[h].p)) c[h] = b[i];
return -1; // x == 0 && y == 0 }
} }

8
}; while(q < h-1 && c[q].out(c[h] ˆ c[h-1])) --h;
bool cmp(pt p1, pt p2){ // Around Origin(0, 0): --> while(q < h-1 && c[h].out(c[q] ˆ c[q+1])) ++q;

GEOMETRY
sort(all(pts), cmp); if(h - q <= 1) return {};
int c1 = p1.cuad(), c2 = p2.cuad(); c[h+1] = c[q];
return c1 == c2 ? p1.y*p2.x < p1.x*p2.y : c1 < c2; vector<pt> s;
} // Around const pt O(x, y): fore(i, q, h) s.pb(c[i] ˆ c[i+1]);
// --> sort(all(pts), [&](pt& pi, pt& pj){ return cmp( return s;
pi - O, pj - O); }); }
8.8
return {INF, pt()};
return {(p - node->pp).norm2(),
8.8 KD Tree node->pp};

KD Tree
}
struct pt{ Node *f = node->fir, *s = node->sec;
ld x, y; ll bf = f->distance(p), bs = s->distance(
pt(){} p);
pt(ld x, ld y): x(x), y(y){} if(bf > bs) swap(bf, bs), swap(f, s);
pt operator+(pt p){ return pt(x+p.x, y+p.y); } auto best = search(p,f);
pt operator-(pt p){ return pt(x-p.x, y-p.y); } if(bs < best.fi) best = min(best, search(
ld operator*(pt p){ return x*p.x + y*p.y; } p, s));
ld norm2(){ return *this * *this; } return best;
bool operator<(pt p)const{ // for sort, convex }
hull/set/map pair<ll, pt> nearest(pt p){ return search(p, root
return x < p.x - eps || (abs(x - p.x) <= ); }
eps && y < p.y - eps); } };
};
inline bool onx(pt a, pt b){ return a.x < b.x; }
inline bool ony(pt a, pt b){ return a.y < b.y; }
// Given a set of N points, answer queries of nearest 8.9 Minkowski Sum
point in O(log(N))
struct Node { struct pt{
pt pp; ld x, y;
ll x0 = inf, x1 = -inf, y0 = inf, y1 = -inf; pt(){}
Node *fir = 0, *sec = 0; pt(ld x, ld y): x(x), y(y){}
inline ll distance(pt p){ pt operator+(pt p){return pt(x + p.x, y + p.y);}
ll x = min(max(x0, p.x), x1); pt operator-(pt p){return pt(x - p.x, y - p.y);}
ld operator%(pt p){return x * p.y - y * p.x;}
43

ll y = min(max(y0, p.y), y1);


return (pt(x, y) - p).norm2(); ld side(pt p, pt q){return (q - p) % (*this - p);}
} };
Node(vector<pt>&& vp): pp(vp[0]){ struct mink_sum{
for(pt& p: vp){ vector<pt> p, q, pol;
x0 = min(x0, p.x), x1 = max(x1, p mink_sum(){}
.x); mink_sum(vector<pt>& p1, vector<pt>& p2, bool inter =
y0 = min(y0, p.y), y1 = max(y1, p 1): p(p1), q(p2){
.y); if(inter) for(auto& [x, y] : q) x = -x, y = -y;
} pol.reserve(sz(p) + sz(q));
if(sz(vp) > 1){ reorder(p), reorder(q);
sort(all(vp), x1 - x0 >= y1 - y0 forn(i, 2) p.pb(p[i]), q.pb(q[i]);
? onx : ony); int i = 0, j = 0;
int m = sz(vp) / 2; while(i+2 < sz(p) || j+2 < sz(q)){
fir = new Node({vp.begin(), vp.
begin() + m}); pol.pb(p[i] + q[j]);
sec = new Node({vp.begin() + m, auto cro = (p[i+1] - p[i]) % (q[j+1] - q[j]);
vp.end()}); i += cro >= -eps;
} j += cro <= eps;
} }
}; }

8
struct KDTree { void reorder(vector<pt> &p){
Node* root; if(p[2].side(p[0], p[1]) < 0) reverse(all(p));

GEOMETRY
KDTree(const vector<pt>& vp):root(new Node({all( int pos = 0;
vp)})) {} forn(i, sz(p)) if(ii{p[i].y, p[i].x} < ii{p[pos].y, p
pair<ll, pt> search(pt p, Node *node){ [pos].x}) pos = i;
if(!node->fir){ // To avoid query point rotate(p.begin(), p.begin() + pos, p.end());
as answer: }
// ADD: if(p == node -> pp) bool has(pt p){
int cnt = 0; int l = st.top(); st.pop();
forn(i, sz(pol)) cnt += p.side(pol[i], pol[(i+1) % sz switch (op) {
(pol)]) >= 0; case ’+’: st.push(l + r); break;
return cnt == sz(pol); case ’-’: st.push(l - r); break;
} case ’*’: st.push(l * r); break;
bool intersect(pt shift = pt(0, 0)){ return has(shift); case ’/’: st.push(l / r); break;
} }
}; // Do polygons p1 and p2+shift intersect? }
}
int evaluate(string& s) {
9 Miscellaneous stack<int> st;
stack<char> op;
bool may_be_unary = true;
9.1 Counting Sort forn(i,sz(s)) {
if (delim(s[i]))
// it suppose that every element is non-negative continue;
// in other case just translate to the right the elements if (s[i] == ’(’) {
void counting_sort(vi &a){ op.push(’(’);
int n = sz(a); may_be_unary = true;
int maximo = *max_element(all(a)); } else if (s[i] == ’)’) {
vector<int> cnt(maximo+1); while (op.top() != ’(’) {
forn(i,n) ++cnt[a[i]]; process_op(st, op.top());
for(int i = 0, j = 0; i <= maximo; ++i) op.pop();
while(cnt[i]--) a[j++] = i; }
} op.pop();
may_be_unary = false;
44

} else if (is_op(s[i])) {
9.2 Expression Parsing char cur_op = s[i];
if (may_be_unary && is_unary(cur_op))
cur_op = -cur_op;
bool delim(char c) { while (sz(op) && (
return c == ’ ’; (cur_op >= 0 && priority(op.top()) >= priority(
} cur_op)) ||
bool is_op(char c) {
(cur_op < 0 && priority(op.top()) >
return c == ’+’ || c == ’-’ || c == ’*’ || c == ’/’; priority(cur_op))
} )) {
bool is_unary(char c) { process_op(st, op.top());
return c == ’+’ || c==’-’; op.pop();
} }
int priority (char op) { op.push(cur_op);
if (op < 0) return 3; // unary operator may_be_unary = true;
if (op == ’+’ || op == ’-’) return 1; } else {
if (op == ’*’ || op == ’/’) return 2; int number = 0;

9
return -1; while (i < sz(s) && isalnum(s[i]))
} number = number * 10 + s[i++] - ’0’;

MISCELLANEOUS
void process_op(stack<int>& st, char op) { --i;
if (op < 0) { st.push(number);
int l = st.top(); st.pop(); may_be_unary = false;
switch (-op) { }
case ’+’: st.push(l); break; }
case ’-’: st.push(-l); break; while(sz(op)){
} process_op(st, op.top());
} else { op.pop();
int r = st.top(); st.pop();
} double m2 = r - (r - l) / 3;
return st.top(); double f1 = f(m1), f2 = f(m2);
} if (f1 < f2) l = m1;
else r = m2;
}
9.3 Ternary Search return f(l); //return the maximum of
f(x) in [l, r]
}
double ternary_search(double l, double r) {
while (r - l > eps) {
double m1 = l + (r - l) / 3;
45
10 Theory Binomial coefficients
Number of ways to pick a multiset of size k from n elements: n+k−1

k
Number of n-tuples of non-negative integers with sum s: s+n−1 , at most s: s+n
 
DP Optimization Theory s−1
 n−1 n

Name Original Recurrence Sufficient Condition From To Number of n-tuples of positive integers with sum s: n−1
CH 1 dp[i] = minj<i {dp[j] + b[j] ∗ b[j] ≥ b[j + 1] Option- O(n2 ) O(n) Number of lattice paths from (0, 0) to (a, b), restricted to east and north steps:
a+b

a[i]} ally a[i] ≤ a[i + 1] a
n
 n1 nk
Multinomial theorem. (a1 + · · · + ak )n =
P
CH 2 dp[i][j] = mink<j {dp[i − b[k] ≥ b[k+1] Option- O(kn2 ) O(kn) P n1 ,...,nk a1 . . . ak , where
1][k] + b[k] ∗ a[j]} ally a[j] ≤ a[j + 1] ni ≥ 0 and ni = n.
D&Q dp[i][j] = mink<j {dp[i − A[i][j] ≤ A[i][j + 1] O(kn2 ) O(kn log n)  
n n!
1][k] + C[k][j]} = M (n1 , . . . , nk ) =
Knuth dp[i][j] = A[i, j − 1] ≤ A[i, j] ≤ O(n3 ) O(n2 ) n1 , . . . , n k n1 ! . . . nk !
mini<k<j {dp[i][k] + A[i + 1, j] M (a, . . . , b, c, . . . ) = M (a + · · · + b, c, . . . )M (a, . . . , b)
dp[k][j]} + C[i][j]
Catalan numbers.
Notes:
(2n)! 2(2n+1)
• Cn = n+1
1 2n

n = (n+1)!n! con n ≥ 0, C0 = 1 y Cn+1 = n+2 Cn
• A[i][j] - the smallest k that gives the optimal answer, for example in dp[i][j] = Pn−1
Cn = i=0 Ci Cn−1−i
dp[i − 1][k] + C[k][j]
• 1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786, 208012, 742900, 2674440,
• C[i][j] - some given cost function 9694845, 35357670
• We can generalize a bit in the following way dp[i] = minj<i {F [j] + b[j] ∗ a[i]}, • Cn is the number of: properly nested sequences of n pairs of parentheses;
46

where F [j] is computed from dp[j] in constant time rooted ordered binary trees with n + 1 leaves; triangulations of a convex
(n + 2)-gon.

Combinatorics Derangements. Number of permutations of n = 0, 1, 2, . . . elements without


Sums fixed points is 1, 0, 1, 2, 9, 44, 265, 1854, 14833, . . . Recurrence: Dn = (n−1)(Dn−1 +
Pn n
 n! n
k = n(n + 1)/2 k = (n−k)!k!
Dn−2 ) = nD  n−1 + (−1) . Corollary: number of permutations with exactly k fixed
Pbk=0 n n−1
n
points is k Dn−k .
+ n−1
  
k = (a + b)(b − a + 1)/2 k =
Pnk=a 2 n+1
 k
n+1
k−1
n
 Stirling numbers of 1st kind. sn,k is (−1)n−k times the number of permu-
k = n(n + 1)(2n + 1)/6 k  = n−k+1 k
Pk=0
n 3 n n−k n tations of n elements with exactly k permutation cycles. |sn,k | = |sn−1,k−1 | + (n −
k = n2 (n + 1)2 /4 = k+1 k Pn k n
Pk=0
n
k+1
n
 n n−1
 1)|sn−1,k |. k=0 sn,k x = x
k 4 = (6n5 + 15n4 + 10n3 − n)/30 k  = n−k nd
Stirling numbers of 2 kind. Sn,k is the number of ways to partition a
Pnk=0 5 n n−k+1
k
n

k = (2n6 + 6n5 + 5n4 − n2 )/12 k = set of n elements into P exactly k non-empty subsets. Sn,k = Sn−1,k−1 + kSn−1,k .
Pnk=0 k n+1
k
28.8
k−1
n
Pnk=0 x k= (x − 1)/(x − 1) 12! ≈ 2 Sn,1 = Sn,n = 1. xn = k=0 Sn,k xk
k=0 kx = (x − (n + 1)xn+1 + nxn+2 )/(x − 1)2 20! ≈ 261.1 Bell numbers. Bn is the number of partitions of n elements. B0 , . . . =
2
1 + x + x + · · · = 1/(1 − x) 1, 1, 2, 5, 15,
P52,n
203,. . .
n Pn
Bn+1 = k=0 k Bk = k=1 Sn,k . Bell triangle: Br = ar,1 = ar−1,r−1 ,
• Hockey-stick identity
Pn i
 n+1
 ar,c = ar−1,c−1 + ar,c−1 .
= Pm−1 1
Pn n+1

i=r r r+1 Bernoulli numbers. k=0 k n = n+1 k=0 k Bk mn+1−k .
Pm m+1  1
• Number of ways to color n-objects with r-colors if all colors must be used at j=0 j Bj = 0. B0 = 1, B1 = − 2 . Bn = 0, for all odd n 6= 1.
least
Pr once Pr Eulerian numbers. E(n, k) is the number of permutations with exactly k
r r
 r−k n

k=0 k (−1) k o k=0 r−k (−1)k (r − k)n descents (i : πi < πi+1 ) / ascents (πi > πi+1 ) / excedances (πi > i) / k + 1 weak
excedances (πi ≥ i). Pollard-ρ. Choose random x1 , and let xi+1 = x2i − 1 (mod n). Test
Formula: E(n, k) = (k + 1)E(n − 1, k) + (n − k)E(n − 1, k − 1). xn = gcd(n, x2k +i −
√ x2k ) as possible n’s factors for k = 0, 1, . . . Expected time to find
Pn−1 x+k
k=0 E(n, k) n .
a factor: O( m), where m is smallest prime power in n’s factorization. That’s
Burnside’s O(n1/4 ) if you check n = pk as a special case before factorization.
P lemma. The number of orbits under group G’s action on set X: n
|X/G| = |G|1
g∈G |Xg |, where Xg = {x ∈ X : g(x) = x}. (“Average number of
Fermat primes. A Fermat prime is a prime of form 22 + 1. The only known
fixed points.”) Fermat primes are 3, 5, 17, 257, 65537. A number of form 2n + 1 is prime only if
Let w(x) be weight of x’s orbit. Sum of all orbits’ weights:
P it is a Fermat prime.
o∈X/G w(o) =
1
P P Fermat’s Theorem. Let m be a prime and x and m coprimes, then:
|G| g∈G x∈Xg w(x).
• xm−1 ≡ 1 mod m

Number Theory • xk mod m = xk mod (m−1)


mod m
Linear diophantine equation. ax + by = c. Let d = gcd(a, b). A solu- • x φ(m)
≡ 1 mod m
tion exists iff d|c. If (x0 , y0 ) is any solution, then all solutions are given by
(x, y) = (x0 + db t, y0 − ad t), t ∈ Z. To find some solution (x0 , y0 ), use extended Perfect numbers. n > 1 is called perfect if it equals sum of its proper divisors
GCD to solve ax0 + by0 = d = gcd(a, b), and multiply its solutions by dc . and 1. Even n is perfect iff n = 2p−1 (2p − 1) and 2p − 1 is prime (Mersenne’s). No
Linear diophantine equation in n variables: a1 x1 + · · · + an xn = c has solu- odd perfect numbers are yet found.
tions iff gcd(a1 , . . . , an )|c. To find some solution, let b = gcd(a2 , . . . , an ), solve Carmichael numbers. A positive composite n is a Carmichael number
a1 x1 + by = c, and iterate with a2 x2 + · · · = y. (an−1 ≡ 1 (mod n) for all a: gcd(a, n) = 1), iff n is square-free, and for all prime
Extended GCD divisors p of n, p − 1 divides n − 1. Qk
Number/sum of divisors. τ (pa1 1 . . . pakk ) = j=1 (aj + 1). σ(pa1 1 . . . pakk ) =
// Finds g = gcd(a,b) and x, y such that ax+by=g. Qk pjaj +1 −1
47

// Bounds: |x|<=b+1, |y|<=a+1. j=1 pj −1 .


τ (n)
void gcdext(int &g, int &x, int &y, int a, int b) Product of divisors. µ(n) = n 2

{ if (b == 0) { g = a; x = 1; y = 0; } k(k+1)
else { gcdext(g, y, x, b, a % b); y = y - (a / b) * x; } } • if p is a prime, then: µ(pk ) = p 2

Multiplicative inverse of a modulo m: x in ax + my = 1, or aφ(m)−1 (mod m). • if a and b are coprimes, then: µ(ab) = µ(a)τ (b) µ(b)τ (a)
Chinese Remainder Theorem. System x ≡ ai (mod mi ) for i = 1, . . . , n, Euler’s phi function. φ(n) = |{m ∈ N, m ≤ n, gcd(m, n) = 1}|.
with pairwise relatively-prime mi has a unique solution modulo M = m1 m2 . . . mn :
φ(m)φ(n) gcd(m,n)
M
x = a1 b1 m 1
+ · · · + an bn mM
n
M
(mod M ), where bi is modular inverse of m i
modulo • φ(mn) = φ(gcd(m,n)) .
mi .
System x ≡ a (mod m), x ≡ b (mod n) has solutions iff a ≡ b (mod g), • φ(p) = p − 1 si p es primo
where g = gcd(m, n). The solution is unique modulo L = mn g , and equals: • φ(pa ) = pa (1 − p1 ) = pa−1 (p − 1)
x ≡ a + T (b − a)m/g ≡ b + S(a − b)n/g (mod L), where S and T are integer
solutions of mT + nS = gcd(m, n). • φ(n) = n(1 − 1
p1 )(1 − 1
p2 )...(1 − 1
pk ) donde pi es primo y divide a n
Prime-counting function. π(n) = |{p ≤ n : p is prime}|. n/ ln(n) < π(n) <
1.3n/ ln(n). π(1000) = 168, π(106 ) = 78498, π(109 ) = 50 847 534. n-th prime Euler’s theorem. aφ(n) ≡ 1 (mod n), if gcd(a, n) = 1.
≈ n ln n. Wilson’s theorem. p is prime iff (p − 1)! ≡ −1 (mod p).
Miller-Rabin’s primality test. Given n = 2r s + 1 with odd s, and a random Mobius function. µ(1) = 1. µ(n) = 0, if n is not squarefree. µ(n) = (−1)s ,
integer 1 < a < n. if n is the product of s distinct
P primes. Let f , F be Pfunctions on positive integers.
j
If as ≡ 1 (mod n) or a2 s ≡ −1 (mod n) for some 0 ≤ j ≤ r − 1, then n is a If for all n ∈ N , F (n) = d|n f (d), then f (n) = d|n µ(d)F ( nd ), and vice versa.
φ(n) = d|n µ(d) nd .
P P
probable prime. With bases 2, 7 and 61, the test indentifies all composites below d|n µ(d) = 1.
232 . Probability of failure for a random a is at most 1/4. 2
P Q P
If f is multiplicative, then d|n µ(d)f (d) = p|n (1 − f (p)), d|n µ(d) f (d) =
Q
(1 + f (p)). Postage stamps/McNuggets problem. Let a, b be relatively-prime inte-
Pp|n
d|n µ(d) = e(n) = [n == 1]. gers. There are exactly 12 (a − 1)(b − 1) numbers not of form ax + by (x, y ≥ 0), and
Sf (n) = p=1 (1 + f (pi ) + f (p2i ) + ... + f (pei i )), p - primes(n).
Q the largest is (a − 1)(b − 1) − 1 = ab − a − b.
  Fermat’s two-squares theorem. Odd prime p can be represented as a sum
Legendre symbol. If p is an odd prime, a ∈ Z, then ap equals 0, if p|a; 1 if a of two squares iff p ≡ 1 (mod 4). A product of two sums of two squares is a sum
  p−1
is a quadratic residue modulo p; and −1 otherwise. Euler’s criterion: ap = a( 2 ) of two squares. Thus, n is a sum of two squares iff every prime of form p = 4k + 3
occurs an even number of times in n’s factorization.
(mod p).
Qk  ki RSA. Let p and q be random distinct large primes, n = pq. Choose a small odd
Jacobi symbol. If n = pa1 1 · · · pakk is odd, then a a

n = i=1 pi . integer e, relatively prime to φ(n) = (p − 1)(q − 1), and let d = e−1 (mod φ(n)).
Primitive roots. If the order of g modulo m (min n > 0: g ≡ 1 (mod m)) n Pairs (e, n) and (d, n) are the public and secret keys, respectively. Encryption is
is φ(m), then g is called a primitive root. If Zm has a primitive root, then it has done by raising a message M ∈ Zn to the power e or d, modulo n.
φ(φ(m)) distinct primitive roots. Zm has a primitive root iff m is one of 2, 4, pk ,
2pk , where p is an odd prime. If Zm has a primitive root g, then for all a coprime to
m, there exists unique integer i = indg (a) modulo φ(m), such that g i ≡ a (mod m). String Algorithms
indg (a) has logarithm-like properties: ind(1) = 0, ind(ab) = ind(a) + ind(b). Burrows-Wheeler inverse transform. Let B[1..n] be the input (last column of
If p is prime and a is not divisible by p, then congruence xn ≡ a (mod p) has sorted matrix of string’s rotations.) Get the first column, A[1..n], by sorting B.
gcd(n, p − 1) solutions if a(p−1)/ gcd(n,p−1) ≡ 1 (mod p), and no solutions otherwise. For each k-th occurence of a character c at index i in A, let next[i] be the index
(Proof sketch: let g be a primitive root, and g i ≡ a (mod p), g u ≡ x (mod p). of corresponding k-th occurence of c in B. The r-th fow of the matrix is A[r],
xn ≡ a (mod p) iff g nu ≡ g i (mod p) iff nu ≡ i (mod p).) A[next[r]], A[next[next[r]]], ...
Discrete logarithm problem. Find x from ax ≡ b (mod m). Can√be solved Huffman’s algorithm. Start with a forest, consisting of isolated vertices.
√ Repeatedly merge two trees with the lowest weights.
in O( m) time and space with a meet-in-the-middle trick. Let n = d me, and
48

x = ny − z. Equation becomes any ≡ baz (mod m). Precompute all values that
the RHS can take for z = 0, 1, . . . , n − 1, and brute force y on the LHS, each time
checking whether there’s a corresponding value for RHS.
Graph Theory
Pythagorean triples. Integer solutions of x2 + y 2 = z 2 All relatively prime Euler’s theorem. For any planar graph, V − E + F = 1 + C, where V is the
triples are given by: x = 2mn, y = m2 −n2 , z = m2 +n2 where m > n, gcd(m, n) = 1 number of graph’s vertices, E is the number of edges, F is the number of faces in
and m 6≡ n (mod 2). All other triples are multiples of these. Equation x2 +y 2 = 2z 2 graph’s planar drawing, and C is the number of connected components. Corollary:
is equivalent to ( x+y 2 x−y 2 2 V − E + F = 2 for a 3D polyhedron.
2 ) +( 2 ) =z .
Vertex covers and independent sets. Let M , C, I be a max matching, a
• Given an arbitrary pair of integers m and n with m > n > 0: min vertex cover, and a max independent set. Then |M | ≤ |C| = N − |I|, with
a = m2 − n2 , b = 2mn, c = m2 + n2 equality for bipartite graphs. Complement of an MVC is always a MIS, and vice
versa. Given a bipartite graph with partitions (A, B), build a network: connect
• The triple generated by Euclid’s formula is primitive if and only if m and n source to A, and B to sink with edges of capacities, equal to the corresponding
are coprime and not both odd. nodes’ weights, or 1 in the unweighted case. Set capacities of the original graph’s
• To generate all Pythagorean triples uniquely: edges to the infinity. Let (S, T ) be a minimum s-t cut. Then a maximum(-weighted)
a = k(m2 − n2 ), b = k(2mn), c = k(m2 + n2 ) independent set is I = (A ∩ S) ∪ (B ∩ T ), and a minimum(-weighted) vertex cover
is C = (A ∩ T ) ∪ (B ∩ S).
• If m and n are two odd integer such that m > n, then: Matrix-tree theorem. Let matrix T = [tij ], where tij is the number of mul-
2 2 2 2
a = mn, b = m −n2 , c = m 2+n tiedges between i and j, for i 6= j, and tii = −degi . Number of spanning trees of
a graph is equal to the determinant of a matrix obtained by deleting any k-th row
• If n = 1 or 2 there are no solutions. Otherwise and k-th column from T .
2 2
n is even: (( n4 − 1)2 + n2 = ( n4 + 1)2 ) Euler tours. Euler tour in an undirected graph exists iff the graph is con-
2 2
n is odd: (( n 2−1 )2 + n2 = ( n 2+1 )2 ) nected and each vertex has an even degree. Euler tour in a directed graph exists
Prufer code of a tree. Label vertices with integers 1 to n. Repeatedly re-
iff in-degree of each vertex equals its out-degree, and underlying undirected graph move the leaf with the smallest label, and output its only neighbor’s label, until
is connected. Construction: only one edge remains. The sequence has length n − 2. Two isomorphic trees have
doit(u):
the same sequence, and every sequence of integers from 1 and n corresponds to a
for each edge e = (u, v) in E, do: erase e, doit(v)
tree. Corollary: the number of labelled trees with n vertices is nn−2 .
prepend u to the list of vertices in the tour
Erdos-Gallai theorem. A sequence of integers {d1 , d2 , . . . , dn }, with n − 1 ≥
Stable marriages problem. While there is a free man m: let w be the most-
P d2 ≥ · · · ≥ dn ≥ 0 is a degree sequence
d1 ≥ Pn of some undirected simple graph iff
preferred woman to whom he has not yet proposed, and propose m to w. If w is di is even and d1 +· · ·+dk ≤ k(k−1)+ i=k+1 min(k, di ) for all k = 1, 2, . . . , n−1.
free, or is engaged to someone whom she prefers less than m, match m with w, else
deny proposal.
Stoer-Wagner’s min-cut algorithm. Start from a set A containing an ar- Games
bitrary vertex.
P While A 6= V , add to A the most tightly connected vertex (z ∈
/A Grundy numbers. For a two-player, normal-play (last to move wins) game on a
such that x∈A w(x, z) is maximized.) Store cut-of-the-phase (the cut between the graph (V, E): G(x) = mex({G(y) : (x, y) ∈ E}), where mex(S) = min{n ≥ 0 : n 6∈
last added vertex and rest of the graph), and merge the two vertices added last. S}. x is losing iff G(x) = 0.
Repeat until the graph is contracted to a single vertex. Minimum cut is one of the Sums of games.
cuts-of-the-phase. • Player chooses a game and makes a move in it. Grundy number of a position
Tarjan’s offline LCA algorithm. (Based on DFS and union-find structure.) is xor of grundy numbers of positions in summed games.

DFS(x): • Player chooses a non-empty subset of games (possibly, all) and makes moves
ancestor[Find(x)] = x in all of them. A position is losing iff each game is in a losing position.
for all children y of x:
• Player chooses a proper subset of games (not empty and not all), and makes
49

DFS(y); Union(x, y); ancestor[Find(x)] = x


seen[x] = true moves in all chosen ones. A position is losing iff grundy numbers of all games
for all queries {x, y}: are equal.
if seen[y] then output "LCA(x, y) is ancestor[Find(y)]"
• Player must move in all games, and loses if can’t move in some game. A
Strongly-connected components. Kosaraju’s algorithm. position is losing if any of the games is in a losing position.
1. Let GT be a transpose G (graph with reversed edges.) Misère Nim. A position with pile sizes a1 , a2 , . . . , an ≥ 1, not all equal to 1,
1. Call DFS(GT ) to compute finishing times f [u] for each vertex u. is losing iff a1 ⊕ a2 ⊕ · · · ⊕ an = 0 (like in normal nim.) A position with n piles of
3. For each vertex u, in the order of decreasing f [u], perform DFS(G, u). size 1 is losing iff n is odd.
4. Each tree in the 3rd step’s DFS forest is a separate SCC.
2-SAT. Build an implication graph with 2 vertices for each variable – for the
variable and its inverse; for each clause x ∨ y add edges (x, y) and (y, x). The Bit tricks
formula is satisfiable iff x and x are in distinct SCCs, for all x. To find a satisfiable Clearing the lowest 1 bit: x & (x - 1), all trailing 1’s: x & (x + 1)
assignment, consider the graph’s SCCs in topological order from sinks to sources Setting the lowest 0 bit: x | (x + 1)
(i.e. Kosaraju’s last step), assigning ‘true’ to all variables of the current SCC (if it Enumerating subsets of a bitmask m:
hasn’t been previously assigned ‘false’), and ‘false’ to all inverses. x=0; do { ...; x=(x+1+˜m)&m; } while (x!=0);
Randomized algorithm for non-bipartite matching. Let G be a sim- __builtin_ctz/__builtin_clz returns the number of trailing/leading zero
ple undirected graph with even |V (G)|. Build a matrix A, which for each edge bits.
(u, v) ∈ E(G) has Ai,j = xi,j , Aj,i = −xi,j , and is zero elsewhere. Tutte’s theorem: __builtin_popcount(unsigned x) counts 1-bits (slower than table lookups).
G has a perfect matching iff det G (a multivariate polynomial) is identically zero. For 64-bit unsigned integer type, use the suffix ‘ll’, i.e. __builtin_popcountll.
Testing the latter can be done by computing the determinant for a few random XOR Let’s say F(L,R) is XOR of subarray from L to R.
values of xi,j ’s over some field. (e.g. Zp for a sufficiently large prime p) Here we use the property that F(L,R)=F(1,R) XOR F(1,L-1)
Math √
Great circle distance or geographical distance
Stirling’s approximation z! = Γ(z + 1) = 2π z z+1/2 e−z (1 + 1
+ 1

139
12z 288z 2 • d = great distance, φ = latitude, λ = longitude, ∆ = difference (all the values
51840z 3 + . . . ) in radians)
2 n
(x−a)
Taylor series. f (x) = f (a)+ x−a 0
1! f (a)+ 2! f (2) (a)+· · ·+ (x−a)
n! f (n) (a)+. . . .
x3 x5 x7
sin x = x − 3! + 5! − 7! + . . . • σ = central angle, angle form for the two vector
3 5
ln x = 2(a + a3 + a5 + . . . ), where a = x−1 2 q
x+1 . ln x = 2 ln x. • d = r ∗ σ, σ = 2 ∗ arcsin( sin2 ( ∆φ 2 ∆λ
3 5 7 2 ) + cos(φ1 ) cos(φ2 ) sin ( 2 ))
arctan x = x − x3 + x5 − x7 + . . . , arctan x = arctan c + arctan 1+xc
x−c
(e.g c=.2)
π = 4 arctan 1, π = 6 arcsin 21 Theorems
Fibonacci Period Si p es primo , π(pk ) = pk−1 π(p)
• There is always a prime between numbers n2 and (n + 1)2 , where n is any
π(2) = 3 π(5) = 20
positive integer
Si n y m son coprimos π(n ∗ m) = lcm(π(n), π(m))
List of Primes • There is an infinite number of pairs of the from {p, p + 2} where both p and
1e5 3 19 43 49 57 69 103 109 129 151 153 p + 2 are primes.
1e6 33 37 39 81 99 117 121 133 171 183
1e7 19 79 103 121 139 141 169 189 223 229 • Every even integer greater than 2 can be expressed as the sum of two primes.
1e8 7 39 49 73 81 123 127 183 213
2-SAT Rules • Every integer greater than 2 can be written as the sum of three primes.
p → q ≡ ¬p ∨ q
• ad ≡ ad mod φ(n) mod n
p → q ≡ ¬q → ¬p
if a ∈ Zn∗ or a ∈
/ Zn∗ and d mod φ(n) 6= 0
p ∨ q ≡ ¬p → q
50

p ∧ q ≡ ¬(p → ¬q) • ad ≡ aφ(n) mod n


¬(p → q) ≡ p ∧ ¬q / Zn∗ and d mod φ(n) = 0
if a ∈
(p → q) ∧ (p → r) ≡ p → (q ∧ r)
(p → q) ∨ (p → r) ≡ p → (q ∨ r) • thus, for all a, n and d (with d ≥ log2 (n))
(p → r) ∧ (q → r) ≡ (p ∧ q) → r ad ≡ aφ(n)+d mod φ(n) mod n
(p → r) ∨ (q → r) ≡ (p ∨ q) → r
(p ∧ q) ∨ (r ∧ s) ≡ (p ∨ r) ∧ (p ∨ s) ∧ (q ∨ r) ∧ (q ∨ s) Law of sines and cosines
• a, b, c: lenghts, A, B, C: opposite angles, d: circumcircle
Summations
Pn 2 n(n+1)(2n+1) • a
= b
= c
=d
• i=1 i = 6
sin(A) sin(B) sin(C)

Pn 3 n(n+1) 2 • c2 = a2 + b2 − 2ab cos(C)


• i=1 i = ( 2 )
Pn 4 n(n+1)(2n+1)(3n2 +3n−1)
Heron’s Formula
• i=1 i = 30
• s= a+b+c
2
Pn 5 (n(n+1))2 (2n2 +2n−1)
• i=1 i = 12
• Area =
p
Pn n+1
s(s − a)(s − b)(s − c)
• i
i=0 x =
x
x−1
−1
para x 6= 1
• a, b, c there are the lenghts of the sides
Compound Interest
Legendre’s Formula Largest power of k, x, such that n! is divisible by k x
• N is the initial population, it grows at a rate of R. So, after X years the
popularion will be N × (1 + R)X • If k is prime, x = n
k + n
k2 + n
k3 + ...
• If k is composite k = k1p1 ∗ k2p2 . . . km
pm
to v) — (sum of lower bounds of outgoing edges from v). For all v, if M[v]¿0
aj
x = min1≤j≤m { pj } where aj is Legendre’s formula for kj then add edge (S,v) with capacity M, otherwise add (v,T) with capacity -M.
If all outgoing edges from S are full, then a feasible flow exists, it is the flow
• Divisor Formulas of n! Find all prime numbers ≤ n {p1 , . . . , pm } Let’s define plus the original lower bounds. maximum flow in a network with both upper
ej as Legendre’s formula for pj and lower capacity constraints, with source s and sink t: add edge (t,s) with
Qm
• Number of divisors of n! The answer is j=1 (ej + 1) capacity infinity. Binary search for the lower bound, check whether a feasible
exists for a network WITHOUT source or sink (B).
e +1
Qm pj j −1
• Sum of divisors of n! The answer is j=1 ej −1 Pick’s Theorem

• A=i+ b
2 −1
Max Flow with Demands Max Flow with Lower bounds of flow for each
edge • A : area of the polygon.
• feasible flow in a network with both upper and lower capacity constraints, no • i : number of interior integer points.
source or sink: capacities are changed to upper bound — lower bound. Add
a new source and a sink. let M[v] = (sum of lower bounds of ingoing edges • b : number of integer points on the boundary.
51

You might also like