Notebook - template for icpc
Notebook - template for icpc
#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
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
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
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;
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
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;
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
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
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
} }
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;
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
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
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
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
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;
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
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
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
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); }
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
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
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];
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
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
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
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
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
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
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.
{ 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
• 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