classical - École normale supérieure · ens ulm 1 École normale supérieure ulm 1 of 24...

24
ENS Ulm 1 École Normale Supérieure ULM 1 of 24 April 2, 2018 14:50 Classical: page 1 Data structures: page 2 Maths: page 7 Bit tricks: page 10 Linear algebra and linear programming: page 10 Geometry: page 12 Graphs: page 13 Flows: page 16 String, languages: page 18 Pre-contest .emacs (line-number-mode 1) (column-number-mode t) (linum-global-mode 1) (menu-bar-mode -99) (tool-bar-mode -99) (global-set-key (kbd "f9") ’compile) Header #include <bits/stdc++.h> #define FOR(i, n) for(lli i = 0; i < (lli)(n); ++i) #define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i) #define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i) #define X(A) get<0>(A) #define Y(A) get<1>(A) #define Z(A) get<2>(A) #define W(A) get<3>(A) #define all(x) begin(x),end(x) #define mp make_pair #define mt make_tuple #define pb push_back //------------------------------------------------------------------------------ using namespace std; using lli = long long int ; using llu = long long unsigned ; using pii = tuple < lli , lli >; using piii = tuple < lli , lli , lli >; using vi = vector < lli >; using vii = vector < pii >; using viii = vector < piii >; using vvi = vector < vi >; using vvii = vector < vii >; using vviii = vector < viii >; using pt = complex < lli >; //------------------------------------------------------------------------------ template < class A, class B> ostream& operator <<(ostream& s, pair<A, B> const & a){ return s << "(" << X(a) << "," << Y(a) << ")" ; } template < class A, class B> ostream& operator <<(ostream& s, tuple<A, B> const & a){ return s << "(" << X(a) << "," << Y(a) << ")" ; } template < class A, class B, class C> ostream& operator <<(ostream& s, tuple<A, B, C> const & a){ return s << "(" << X(a) << "," << Y(a) << "," << Z(a) << ")" ; } template < class T> ostream& print_collection(ostream& s, T const & a); template < class T> ostream& operator <<(ostream& s, vector<T> const & a) { return print_collection(a); template < class T> ostream& operator <<(ostream& s, set<T> const & a) { return print_collection(a); } template < class T> ostream& print_collection(ostream& s, T const & a){ for ( auto it = begin(a); it != end(a); ++it) { s << *it; if (next(it) != end(a)) s << "" ; } return s; } Classical Longest increasing subsequence — O(N log N ) vi lis( vi const & V) { lli N = V.size(); lli A[N]; // current longest sequences of length... vi I(N); // indices of A vi B(N); // back int k = 0; FOR (i, N){ int j = lower_bound(A, A + k, V[i]) - A; if (j == k) { A[k] = V[i]; I[k] = i; k += 1; } else if (V[i] < A[j]) { A[j] = V[i]; I[j] = i; } if (i && j && j-1 < k) { B[i] = I[j-1]; } } vi L(k); // Get the longest sequence from back edges

Upload: vudieu

Post on 07-May-2018

216 views

Category:

Documents


1 download

TRANSCRIPT

ENS Ulm 1 École Normale Supérieure ULM 1 of 24

April 2, 2018 14:50Classical: page 1Data structures: page 2Maths: page 7Bit tricks: page 10Linear algebra and linear programming: page 10Geometry: page 12Graphs: page 13Flows: page 16String, languages: page 18

Pre-contest.emacs(line-number-mode 1)(column-number-mode t)(linum-global-mode 1)(menu-bar-mode -99)(tool-bar-mode -99)(global-set-key (kbd "f9") ’compile)

Header

#include <bits/stdc ++.h>

#define FOR(i, n) for(lli i = 0; i < (lli)(n); ++i)#define FORU(i, j, k) for(lli i = (j); i <= (lli)(k); ++i)#define FORD(i, j, k) for(lli i = (j); i >= (lli)(k); --i)

#define X(A) get <0>(A)#define Y(A) get <1>(A)#define Z(A) get <2>(A)#define W(A) get <3>(A)

#define all(x) begin(x),end(x)#define mp make_pair#define mt make_tuple#define pb push_back

// ------------------------------------------------------------------------------

using namespace std;using lli = long long int;using llu = long long unsigned;

using pii = tuple <lli , lli >;using piii = tuple <lli , lli , lli >;using vi = vector <lli >;using vii = vector <pii >;using viii = vector <piii >;using vvi = vector <vi >;using vvii = vector <vii >;using vviii = vector <viii >;using pt = complex <lli >;

// ------------------------------------------------------------------------------

template <class A, class B>ostream& operator <<(ostream& s, pair <A, B> const& a){

return s << "(" << X(a) << "," << Y(a) << ")";}

template <class A, class B>ostream& operator <<(ostream& s, tuple <A, B> const& a){

return s << "(" << X(a) << "," << Y(a) << ")";}

template <class A, class B, class C>ostream& operator <<(ostream& s, tuple <A, B, C> const& a){

return s << "(" << X(a) << "," << Y(a) << "," << Z(a) << ")";}

template <class T>ostream& print_collection(ostream& s, T const& a);

template <class T>ostream& operator <<(ostream& s, vector <T> const& a) { return print_collection(a); }template <class T>ostream& operator <<(ostream& s, set <T> const& a) { return print_collection(a); }

template <class T>ostream& print_collection(ostream& s, T const& a){

for(auto it = begin(a); it != end(a); ++it) {s << *it; if(next(it) != end(a)) s << "␣";

}return s;

}

ClassicalLongest increasing subsequence — O(N logN)

vi lis(vi const& V) {lli N = V.size ();lli A[N]; // current longest sequences of length ...vi I(N); // indices of Avi B(N); // backint k = 0;FOR(i, N){

int j = lower_bound(A, A + k, V[i]) - A;if(j == k) {

A[k] = V[i];I[k] = i;k += 1;

} else if(V[i] < A[j]) {A[j] = V[i];I[j] = i;

}if(i && j && j-1 < k) { B[i] = I[j-1]; }

}vi L(k); // Get the longest sequence from back edges

ENS Ulm 1 École Normale Supérieure ULM 2 of 24

int cur = I[k-1];FORD(i, k-1, 0) {

L[i] = V[cur];cur = B[cur];

}return L;

}

Combine hashes

template <typename T>inline void hash_combine (size_t& seed , const T& val){

seed ^= hash <T>()( val) + 0x9e3779b9 + (seed <<6) + (seed >>2);}

Data stucturesSegment tree — O(logN) range update O(logN) range query

struct node {node() : sum(0), dsum (0){ }lli sum , dsum;

};

struct tree {lli n;vector <node > A;tree(lli n_) : n((lli)1<<(lli)(log2(n_)+1)) , A(2*n) { }

void push(lli i, lli a, lli b){if(i < N){

lli c = (a+b)/2;if(A[i].dsum){

add__ (2*i , a , c, A[i].dsum);add__ (2*i+1, c+1, b, A[i].dsum);A[i].dsum = 0;

}}

}

void update(lli i){A[i].sum = A[2*i].sum + A[2*i+1]. sum;

}

void add__(lli i, lli a, lli b, lli v){A[i].dsum += v;A[i].sum += (b-a+1) * v;

}

void add_(lli i, lli a, lli b, lli l, lli r, lli v){if(l > b) return;if(r < a) return;if(l <= a && b <= r){

add__(i, a, b, v);return;

}push(i, a, b);

lli c = (a+b)/2;add_ (2*i , a , c, l, r, v);add_ (2*i+1, c+1, b, l, r, v);update(i);

}

void add(lli l, lli r, lli v){add_(1, 0, n-1, l, r, v);

}};

Cartesian tree — Augmented balanced binary tree

// y is only used to balance the tree , it needs to be random// Remove x and change split if a binary search tree is not needed// To augment the cartesian tree :// - Add fields to treap// - update () recompute from subtrees// - push() pushes lazy updates to subtreesstruct treap {

treap(lli x_) : l(0), r(0), x(x_), size(1), y(rand ()){ }treap *l, *r;lli x;lli size;lli y;

};

lli get_size(treap* a){ return a?a->size :0; }

void update(treap* a){if(a){

a->size = 1;if(a->l) a->size += a->l->size;if(a->r) a->size += a->r->size;

}}

void push(treap *){ }

treap* merge(treap* a, treap* b){if(a == 0) return b;if(b == 0) return a;push(a); push(b);if(a->y < b->y){

a->r = merge(a->r, b);update(a);return a;

}else{b->l = merge(a, b->l);update(b);return b;

}}

// Split with explicit keys// Use size to split at a positiontuple <treap*, treap*> split(treap* a, pii x){

ENS Ulm 1 École Normale Supérieure ULM 3 of 24

if(a == 0) return mt(nullptr , nullptr );push(a);if(x <= a->x){

auto p = split(a->l, x);a->l = Y(p);update(a);return mt(X(p), a);

}else{auto p = split(a->r, x);a->r = X(p);update(a);return mt(a, Y(p));

}}

treap* insert(treap* a, lli x){auto p = split(a, x);return merge(merge(X(p), new treap(x)), Y(p));

}

BIT — O(logN) read O(logN) update

// Compute / Modify prefix sums for any monoid (usually plus , min , max)struct BIT {

vi A;BIT(lli n) : A(n+1){ }lli get(lli i){

i += 1;lli r = 0;for(; i > 0; i -= i &-i){

r += A[i];}return r;

}void add(lli i, lli v){

i += 1;for(; i < A.size (); i += i & -i){

A[i] += v;}

}};

Union find

struct uf{vi A;uf(lli n) : A(i){ FOR(i, n) A[i] = i; }lli find(lli a) {

return p[a] == a ? a : p[a] = A(p[a]);}void unite(lli a, lli b) {

p[find(a)] = find(b);}

};

Link-cut tree

namespace link_cut {// change min to change augmentation// create edge -node to augment edges

struct node {node (){ }

node(lli cost_ , lli edge_) : cost(mt(cost_ , edge_ )){mcost = cost;

}pii cost;pii mcost;

node *p = 0, *cs[2] = {0, 0};bool isroot () const { return !p||( this!=p->cs[0]&& this!=p->cs[1]); }lli dir() const { return this==p->cs[1]; }

bool flip = 0;};

void push(node* n){if(n->flip){

swap(n->cs[0], n->cs [1]);FOR(i, 2) if(n->cs[i]) n->cs[i]->flip ^= 1;n->flip = 0;

}}

void update(node* n){if(n){

n->mcost = n->cost;FOR(i, 2) if(n->cs[i]) n->mcost = min(n->mcost , n->cs[i]->mcost);

}}

void rotate(node* n){lli d = n->dir ();node *p = n->p, *b = n->cs[1-d];if(!p->isroot ()) p->p->cs[p->dir()] = n;n->p = p->p;n->cs[1-d] = p; p->p = n;p->cs[d] = b; if(b) b->p = p;update(n); update(p); update(n->p);

}

void splay(node* n){push(n);while (!n->isroot ()){

if(n->p->p) push(n->p->p);push(n->p); push(n);if(n->p->isroot ()) {

rotate(n);} else if(n->dir() == n->p->dir ()) {

rotate(n->p); rotate(n);}else{

rotate(n); rotate(n);

ENS Ulm 1 École Normale Supérieure ULM 4 of 24

}}

}

node* leftmost(node* n){while(n->cs[0]) n = n->cs[0];return n;

}

void splice(node* x){push(x->p);x->p->cs[1] = x;update(x->p);

}

void expose(node* x){{ node* y = x; while(y) { splay(y); y = y->p; } }{ node* y = x; while(y->p) { splice(y); y = y->p; }}splay(x);

}

void evert(node* n){expose(n);if(n->cs [0]){

n->cs[0]->flip ^= 1;n->cs[0] = 0;update(n);

}}

void link(node* x, node* y){evert(y); y->p = x;

}

void cut(node* x, node* y){evert(x); expose(y);y->cs[0] = 0; x->p = 0;update(y);

}

pii path(node* x, node* y){evert(x);expose(y);return min(y->cs[0]->mcost , y->cost);

}

}

Wavelet tree

struct wavelet_tree {lli lo=0, hi=0;wavelet_tree *l = 0, *r = 0;vector <int > b;

wavelet_tree () = default;

~wavelet_tree (){if(l) delete l;if(r) delete r;

}

wavelet_tree(vector <lli > A) :wavelet_tree(begin(A),end(A),* min_element(all(A)),* max_element(all(A))) { }

template <typename IT>wavelet_tree(IT from , IT to, lli lo_ , lli hi_) {

lo=lo_; hi=hi_;lli mi = lo + (hi-lo)/2;auto f = [&]( lli x) { return x <= mi; };b.reserve(distance(from ,to)+1); b.pb(0);for(auto it = from; it != to; ++it) b.pb(b.back() + f(*it));auto mit = stable_partition(from ,to,f);if(lo == hi || from == to) return;l = new wavelet_tree(from ,mit ,lo,mi);r = new wavelet_tree(mit ,to,mi+1,hi);

}

/** tr.swap(i,A[i],A[i+1]); swap(A[i],A[i+1]) :* swaps values at positions i and i+1*/

void swap(int i, lli si, lli sj) {if(si==sj) return;if(lo == hi) {

return;assert (0);

}else{lli mi = lo + (hi-lo)/2;if(si <=mi&&sj <=mi){

l->swap(b[i],si,sj);}else if(si >mi&&sj >mi){

r->swap(i-b[i],si,sj);}else if(si <=mi){

b[i+1] -= 1;}else{

b[i+1] += 1;}

}}

/** kth(l,r,k) : k-th value of sorted subsequence A[l]...A[r]*/

lli kth(lli l, lli r, int k) {assert(l <= r);assert(k < r-l+1);if(lo == hi) return lo;int inleft = b[r+1]-b[l];if(k < inleft) return this ->l->kth(b[l],b[r+1]-1,k);else return this ->r->kth(l-b[l],r-b[r+1],k-inleft );

}

ENS Ulm 1 École Normale Supérieure ULM 5 of 24

/** cnt(l,r,y) : number of occurences of y in A[l]..A[r]*/

int cnt(lli l, lli r, lli y) {if(l>r) return 0;if(lo == hi) {

if(lo == y) {return r-l+1;

}else{return 0;

}}else{

lli mi = lo + (hi-lo)/2;if(y<=mi) {

return this ->l->cnt(b[l],b[r+1]-1,y);}else{

return this ->r->cnt(l-b[l],r-b[r+1],y);}

}}

};

Dynamic (upper) convex hull

using line_t = long long int; // double;const line_t is_query = -(1ll <<62); // -1e18;

struct Line {line_t m, b;mutable function <const Line*()> succ;bool operator <(const Line& rhs) const {

if (rhs.b != is_query) return m < rhs.m;const Line* s = succ ();if (!s) return 0;line_t x = rhs.m;return b - s->b < (s->m - m) * x;

}};

struct HullDynamic : public multiset <Line > {bool bad(iterator y) {

auto z = next(y);if (y == begin ()) {

if (z == end()) return 0;return y->m == z->m && y->b <= z->b;

}auto x = prev(y);if (z == end()) return y->m == x->m && y->b <= x->b;return (x->b - y->b)*(z->m - y->m) >= (y->b - z->b)*(y->m - x->m);

}void insert_line(line_t m, line_t b) {

auto y = insert ({ m, b });y->succ = [=] { return next(y) == end() ? 0 : &*next(y); };if (bad(y)) { erase(y); return; }while (next(y) != end() && bad(next(y))) erase(next(y));while (y != begin () && bad(prev(y))) erase(prev(y));

}

line_t query_max(line_t x) {auto l = *lower_bound ((Line) { x, is_query });return l.m * x + l.b;

}};

LiChao segment tree

struct fn {fn() : a(0), b(-1e100) { }fn(long double a_ , long double b_) : a(a_), b(b_) { }long double a, b;

long double operator ()( lli x) const { return a*(long double)x + b; }};

struct LiChao {lli lo, hi, mi;fn f;LiChao *l, *r;

LiChao(lli lo_ , lli hi_ , fn f_) : lo(lo_), hi(hi_), f(f_) {mi = lo+(hi-lo)/2;l = r = 0;

}

LiChao& left() {if(!l) l = new LiChao(lo , mi , fn());return *l;

}

LiChao& right() {if(!r) r = new LiChao(mi+1, hi, fn());return *r;

}

void add(fn g) {auto fl = f(lo), fr = f(hi);auto gl = g(lo), gr = g(hi);if(fl >= gl && fr >= gr) return; // Always worseif(fl < gl && fr < gr) { f = g; return; } // Always betterif(fl < gl) swap(f, g); // Trick to know where the intersection isif(f(mi) > g(mi)) right (). add(g);else { swap(f,g); left ().add(g); }

}

long double qu(lli x) {if(lo == hi) return f(x);if(x > mi) { return r?max(f(x),right ().qu(x)):f(x); }else { return l?max(f(x),left ().qu(x)):f(x); }

}};

Min-Sum segment tree

const lli infty = 1e16;

ENS Ulm 1 École Normale Supérieure ULM 6 of 24

struct segment_tree {

struct node {node (){

maxVal = infty;maxCnt = 1;sndMax = -1;sum = 0;delta = infty;

}lli maxVal , maxCnt;lli sndMax;lli sum;lli delta;

void combine(node &a, node& b) {maxVal = max(a.maxVal , b.maxVal );maxCnt = 0;if(maxVal == a.maxVal) maxCnt += a.maxCnt;if(maxVal == b.maxVal) maxCnt += b.maxCnt;sndMax = max(a.sndMax ,b.sndMax );if(maxVal != a.maxVal) sndMax = max(sndMax ,a.maxVal );if(maxVal != b.maxVal) sndMax = max(sndMax ,b.maxVal );sum = a.sum+b.sum;

}};

int n;vector <node > A;segment_tree(int n_) : n((int)1<<(int)(log2(n_)+1)), A(2*n) {

build ();}

void update(int i) {if(i < n) {

A[i]. combine(A[2*i],A[2*i+1]);}

}

void build (){FORD(i,n-1,1) update(i);

}

void push(int i, int a, int b){if(i < n){

int c = (a+b)/2;if(A[i]. delta != infty) {

setr__ (2*i,a,c,A[i].delta);setr__ (2*i+1,c+1,b,A[i].delta);A[i]. delta = infty;

}}

}

void setr__(int i, int a, int b, lli v){if(v >= A[i]. maxVal) return;

if(v >= A[i]. sndMax) {if(A[i]. maxVal != infty) {

A[i].sum -= A[i]. maxCnt * A[i]. maxVal;}A[i]. maxVal = v;A[i].sum += A[i]. maxCnt * A[i]. maxVal;A[i]. delta = v;return;

}assert(i<n);setr___(i,a,b,a,b,v);

}

void setr___(int i, int a, int b, lli l, lli r, lli v) {int c = (a+b)/2;setr_ (2*i , a , c, l, r, v);setr_ (2*i+1, c+1, b, l, r, v);update(i);

}

void setr_(int i, int a, int b, int l, int r, lli v) {if(l > b) return;if(r < a) return;push(i,a,b);if(l <= a && b <= r) { setr__(i, a, b, v); return; }setr___(i,a,b,l,r,v);

}

// Min all elements in [l,r] with vvoid setr(int l, int r, lli v){

setr_(1, 0, n-1, l, r, v);}

lli get_(int i, int a, int b, int l, int r) {if(l > b) return 0;if(r < a) return 0;push(i,a,b);if(l <= a && b <= r){

return A[i].sum;}int c = (a+b)/2;return get_ (2*i , a , c, l, r) + get_ (2*i+1, c+1, b, l, r);

}

// Sum of non infinity elements in [l,r]lli get(int l, int r){

return get_(1, 0, n-1, l, r);}

};

g++ ordered statistics trees

#include <ext/pb_ds/assoc_container.hpp >#include <ext/pb_ds/tree_policy.hpp >using namespace __gnu_pbds;

using ordered_set =

ENS Ulm 1 École Normale Supérieure ULM 7 of 24

tree <int , null_type , less <int >, rb_tree_tag , tree_order_statistics_node_update >;

ordered_set X;X.insert (1); X.insert (2); X.insert (4); X.insert (8); X.insert (16);

cout << *X.find_by_order (1) << endl; // 2cout << *X.find_by_order (2) << endl; // 4cout << *X.find_by_order (4) << endl; // 16

cout << (end(X) == X.find_by_order (6)) << endl; // true

cout << X.order_of_key (-5) << endl; // 0cout << X.order_of_key (1) << endl; // 0cout << X.order_of_key (3) << endl; // 2cout << X.order_of_key (4) << endl; // 2cout << X.order_of_key (400) << endl; // 5

MathsBernoulli numbers:

n 0 1 2 4 6 8 10 12Bn 1 -1/2 1/6 -1/30 1/42 -1/30 5/66 -691/2730

B2n+3 = 0

(m+ 1)Bm = −∑m−1k=0

( km+1

)Bk∑n

k=1 km = 1

m+1

∑mk=0

(m+1k

)Bkn

m+1−k.

∑b−1k=a f(k) =

∫ ba f(t)dt+

∑nk=1

Bkk!

(f (k−1)(b)− f (k−1)(a)

)+

(−1)n+1

n!

∫ ba Bn(t)f

(n)(t)dt.

n ≥ 1. ζ(2n) = (−1)n−122n−1 B2n(2n)!

π2n.

Extended GCD and modular inverse (ie. with Bezout coefficients)

pii egcd(lli a, lli b) {if(a%b==0) {

return mt(0,1);}else{

pii p = egcd(b,a%b);int u=p.x(), v=p.y();return mt(v, u-(a/b)*v);

}}

// solve x*a = b [mod m]int solveInv(lli a, lli b, lli m) {

if(b==0) return 0;pii p = egcd(a,m);lli g=__gcd(m,a);return (((b/g)*p.x())%m+m)%m;

}

Miller-Rabin primality testing

// Miller -Rabin__int128 fexp(__int128 a, __int128 b, __int128 m) {

if(b==0) return 1;

if(b==1) return a%m;__int128 c = fexp(a,b/2,m);c=c*c%m;if(b&1) c=c*(a%m)%m;return c;

}

bool f(__int128 n, __int128 a) {if(n==a) return 1;int s = __builtin_ctzll(n-1);__int128 d = (n-1)>>s;if(fexp(a,d,n) == 1) return 1;FOR(r,s) if(fexp(a,d<<r,n) == n-1) return 1;return 0;

}

bool is_prime(__int128 n) {if(n != 2 && n%2==0) return 0;if(n==46856248255981) return 0;if(!f(n,2)) return 0;if(!f(n,3)) return 0;if(!f(n,7)) return 0;if(!f(n,61)) return 0;if(!f(n ,24251)) return 0;return 1;

}

// Pollard -Rho factorization__int128 g(__int128 x, __int128 n, __int128 c){

return (c + (x*x)%n) % n;}

void rec(__int128 n, vector <__int128 > &v){if(n == 1) return;if(n % 2 == 0){

v.push_back (2);rec(n/2, v);return;

}if(is_prime(n)){

v.push_back(n);return;

}__int128 a, b, c;while (1){

a = rand() % (n-2) + 2;b = a;c = rand() % 20 + 1;do{

a = g(a, n, c);b = g(g(b, n, c), n, c);

} while(__gcd <lli >(abs <lli >(a-b), n) == 1);if(a != b) break;

}__int128 x = __gcd <lli >(abs <lli >(a-b), n);rec(x, v);

ENS Ulm 1 École Normale Supérieure ULM 8 of 24

rec(n/x, v);}

vector <__int128 > factorize(__int128 n){vector <__int128 > R;rec(n, R);sort(all(R));return R;

}

Count inversions — O(N logN)

// Count number of positions i < j with A[i] > A[j]lli inversions(vi const& A){

// Coordinate compressionset <lli > ALLX; for(auto x : A) ALLX.pb(x);vi TOX; unordered_map <lli , lli > FROMX;for(auto x : ALLX) { FROMX[x] = TOX.size (); TOX.pb(x); }// Binary indexed treeBIT B(TOX.size() + 1);lli r = 0;FORD(i, A.size()-1, 0){

r += B.get(FROMX[A[i]]);B.add(FROMX[A[i]] + 1, 1);

}return r;

}

FFT — O(N logN)

namespace Mul {const double pi = acos ( -1.0);

struct Complex {double re,im;Complex( double _re=0, double _im=0 ):re(_re),im(_im) {}Complex operator +( const Complex &x ) const { return {re+x.re ,im+x.im}; }Complex operator -( const Complex &x ) const { return {re-x.re ,im-x.im}; }Complex operator *( const Complex &x ) const{ return {re*x.re-im*x.im,re*x.im+im*x.re}; }

};

void fft(vector <Complex > &a, int dir){int n=a.size ();for( int i=0,j=1; j<n-1; j++ ){

for( int k=n>>1; k>(i^=k); k>>=1 );if( i<j ) swap(a[i],a[j]);

}for(int m=1; m+m<=n; m<<=1){

Complex wm(cos(dir*pi/m),sin(dir*pi/m));for(int k=0; k<n; k+=m+m){

Complex w=1;for(int j=k; j<k+m; j++){

Complex u=a[j],v=a[j+m]*w;a[j]=u+v;a[j+m]=u-v;w=w*wm;

}}

}}

void mul(int na, const int *a, int nb, const int *b, int *c) {static vector <Complex > x,y;assert(na >0 && nb >0);int n=1;while(n < 2*max(na,nb)) n *= 2;x.resize(n);y.resize(n);FOR(i,n) x[i] = y[i] = 0;FOR(i,na) x[i] = a[i];FOR(i,nb) y[i] = b[i];fft(x,+1);fft(y,+1);FOR(i,n) x[i] = x[i]*y[i];fft(x,-1);FOR(i,n) x[i].re /= n;FOR(i,na+nb -1) c[i] = x[i].re+0.5;

}

vector <int > mul(const vector <int > &a, const vector <int > &b) {int na=a.size(),nb=b.size ();assert(na >0 && nb >0);vector <int > c(na+nb -1);mul(na,a.data(),nb,b.data(),c.data ());return c;

}};

NTT — O(N logN)

// MOD should be prime , G = (prim root )^119// 998244353 = 119*(1 < <23)+1 , G = 3^119 = 15311432// 985661441 = 235*(1 < <22)+1 , G = 3^235 = 79986183// 1012924417 = 483*(1 < <21)+1 , G = 5^483 = 673144645template <lli MOD = 119*(1 < <23) + 1, lli G = 15311432 >struct NTT {

// (MOD -1) should be divisible by 2**Nvoid ntt(vector <lli >& a, lli h){

lli N = a.size ();for(lli m = N; m >= 2; m /= 2){

lli mh = m/2, w = 1;FOR(i, mh){

for(lli j = i; j < N; j += m){lli k = j+mh;lli x = (a[j]-a[k]);a[j] += a[k];if(a[j] >= MOD) a[j] -= MOD;a[k] = (w*x) % MOD;if(a[k] < 0) a[k] += MOD;

}w = (w*h) % MOD;

}h = (h*h) % MOD;

ENS Ulm 1 École Normale Supérieure ULM 9 of 24

}lli i = 0;FORU(j, 1, N-2){

for(lli k = N/2; k > (i^=k); k/=2);if(j<i) swap(a[i],a[j]);

}}

// Multiply polynomials a and bvector <lli > mult(vector <lli > a, vector <lli > b) {

lli n = a.size() + b.size ();lli N = 1;while(N < n) N *= 2;a.resize(N); b.resize(N);assert ((MOD -1)%N==0);lli h=fexp(G, (MOD -1)/N, MOD);ntt(a,h); ntt(b,h);FOR(i,N) (a[i] *= b[i]) %= MOD;h = invmod(h,MOD);ntt(a,h);h = invmod(N,MOD);FOR(i,N) (a[i] *= h) %= MOD;while (!a.empty () && a.back() == 0) a.pop_back ();return a;

}};

FWHT (XOR-convolution) — O(N logN)

void fwht(lli *data , int dim) {for(int len = 1; 2 * len <= dim; len <<= 1) {

for(int i = 0; i < dim; i += 2 * len) {for(int j = 0; j < len; j++) {

lli a = data[i + j];lli b = data[i + j + len];data[i + j] = (a + b) % MOD;data[i + j + len] = (MOD + a - b) % MOD;

}}

}}

// lli *data = new lli[1<<n];// fwht(data ,1<<n);// FOR(i,1<<n) data[i] = fexp(data[i],POWER);// fwht(data ,1<<n);// lli im = invmod(1<<n);// FOR(i,1<<n) (data[i] *= im) %= MOD;

AND-convolution (Yates’ algorithm) — O(N logN)

Note : OR = NOT ◦ AND ◦ NOTPeut être utilise pour trouver une couverture de taille minimale en temps O(n2n) : Initializer P [m] = 1 pourm ∈ S, calculer Q = transform(P ), et trouver k minimal tel que transform−1(Qk)[0] = 1.Couverture minimale par des cliques / Coloriage minimal se réduisent à ce problème.

// Transforms P in-place// size should be a power of 2

// O(N log N)void transform(int size , lli *P, bool inv) {

for(int len = 1; 2 * len <= size; len <<= 1) {for(int i = 0; i < size; i += 2 * len) {

for(int j = 0; j < len; j++) {lli u = P[i + j];lli v = P[i + len + j];

if (!inv) {P[i + j] = v;P[i + len + j] = (u + v) % MOD;

} else {P[i + j] = (v-u+MOD) % MOD;P[i + len + j] = u;

}}

}}

}

// Evaluates the inverse transform of P in 0// !!! P is modified !!!lli transform_inv0(int size , lli *P) {

for(int len = 1; 2 * len <= size; len <<= 1) {for(int i = 0; i < size; i += 2 * len) {

lli u = P[i];lli v = P[i + len];P[i] = (v-u+MOD) % MOD;P[i + len] = u;

}}return P[0];

}

Polynomial divisionf, g ∈ R[x], g monic, f = gq + r, deg(r) < deg(g). Then Rev(q) = Rev(g)−1Rev(f) [xdeg(f)−deg(g)].Inverse mod xl: Given a with ah = 1 mod xl, h = h0 +h1xl, a = a+ xlb, ah = 1 mod x2l if b = −a(h1a+ c)mod xl where ah0 = 1 + cxl.

Berlekamp-Massey

def berlekamp_massey(l):m = len(l) - 1assert (m % 2 == 1)n = (m + 1) // 2r0 = [Fraction (0)] * (2 * n) + [Fraction (1)]r1 = poly1 ([ Fraction(l[m - i]) for i in range(m + 1)])v0 , v1 = [], [Fraction (1)]while len(r1) - 1 >= n:

q, r = divmod1(r0, r1)v0 , v1 = v1, sub1(v0, mul1(q, v1))r0 , r1 = r1, r

lc = v1[-1]return [x / lc for x in v1]

ENS Ulm 1 École Normale Supérieure ULM 10 of 24

BittricksClassical

// Enumerate subsets of masksubset = mask;do {

//...subset = (subset - 1) & mask;

} while (subset != mask);

// Is x a power of 2 ?!(x & (x - 1))

// Isolate least significant bit set to 1x & (-x)

// fast integer log2int ilog2(int x){ return 31 - __builtin_clz(x); }

Others :x+ (∼ x) = −1

Builtinsunsigned long long versions. Remove ll for unsigned versions. x is the input.__builtin_ffsll 1 plus index of the least significant 1-bit of x. If x is zero, returns zero.__builtin_clzll Number of 0-bits in x starting from the most significant. Result undefined if x is 0.__builtin_ctzll Number of 0-bits in x starting from the least significant. Result undefined if x is 0.__builtin_popcountll Number of 1-bits in x.__builtin_parityll Number of 1-bits of x modulo 2.

Linear algebra and linear programmingLinear system in Z/2Z — fast O(N3), with bitsets

template <int N> // N = dimensionstruct gauss {

bitset <N> A[N]; // upper diagonal matrix (free family)int V[N]; int nv=0; // identify the columnsbitset <N> B[N]; // how elements of A are generated ?

gauss () { reset (); }void reset() {

// memset(this ,0,sizeof(gauss <N>)); should work as wellFOR(i,N) A[i].reset ();nv=0;FOR(i,N) B[i].reset ();

}

// add a matrix column (a vector in the free family)void add(int id, bitset <N> x) {

if(nv == N) return;bitset <N> y; y[nv]=1;FOR(i,N) if(x[i]) {

if(A[i][i]) { x ^= A[i]; y ^= B[i]; }

else { A[i] = x; V[nv++] = id; B[i] = y; return; }}

}

// reach a vector x// returns true when possible , false otherwise// y contains the vectors of V usedbool solve(bitset <N> x, bitset <N> &y){

y.reset ();FOR(i,N) if(x[i]&&A[i][i]) {

x ^= A[i];y ^= B[i];

}if(x.any()) return false;return true;

}};

// example usage : solve a linear system in Z/2Z// M is a matrix (list of columns)// X is a vector// solves M Y = X// returns in Y the indices of columns of M with xor Xconst int N=1000;bool solve(vector <bitset <N> > M, bitset <N> X, vi &Y) {

Y.clear ();gauss <N> G;FOR(i,M.size ()) {

G.add(i, M[i]);}bitset <N> y;if(!G.solve(X,y)) return false;FOR(i,N) if(y[i]) Y.pb(G.V[i]);return true;

}

Linear system in R — O(N3)

// should also work with rationals with minor changes

double EPS = 1e-6;

struct gauss {

using T = double;using vd = vector <T>;using vvd = vector <vd >;

int N;vvd A; // upper diagonal matrix (free family)vi V;vvd B; // how elements of A are generated ?

gauss(int N) { reset(N); }void reset(int N_) {

N=N_;

ENS Ulm 1 École Normale Supérieure ULM 11 of 24

A.assign(N,vd(N,0));V.clear ();B.assign(N,vd(N,0));

}

// add a matrix column (a vector in the free family)void add(int id, vd x) {

if(V.size() == N) return;assert(x.size() == N);vd y(N); y[V.size ()] = 1;FOR(i,N) if(abs(x[i]) > EPS) {

if(abs(A[i][i]) > EPS) {double c = x[i] / A[i][i];FOR(j,N) x[j] -= A[i][j] * c;FOR(j,N) y[j] += B[i][j] * c;

} else {A[i] = x;V.pb(id);B[i] = y;return;

}}

}

// to write solve : copy paste add and modify itbool solve(int id , vd x, vd& y) {

assert(x.size() == N);y.assign(N, 0);FOR(i,N) if(abs(x[i]) > EPS) {

if(abs(A[i][i]) > EPS) {double c = x[i] / A[i][i];FOR(j,N) x[j] -= A[i][j] * c;FOR(j,N) y[j] += B[i][j] * c;

} else {return false;

}}return true;

}};

LUP — O(N3)

using vd = vector <double >;using vvd = vector <vd >;using LUP = tuple <vd, vvd , vvd >;

const double eps = 1e-10;

// Finds P, L, U such that P * A = L * U// P : permutation matrix// L : matrice triangulaire inferieure de diagonale 1// U : matrice triangulare superieure// Determinant : diagonal product of ULUP LUP_decomposition(vvd const& A) {

lli N = A.size ();vd P(N); FOR(i, N) P[i] = i;

vvd L(N, vd(N)), U(N, vd(N));FOR(k, N){

lli bR = 0;double bV = 0;FORU(i, k, N-1) if(abs(A[i][k]) > bV){

bV = abs(A[i][k]);bR = i;

}if(bR < eps) { goto fail; /* A is not invertible */ }swap(P[k], P[bR]);FOR(c, N) swap(A[k][c], A[bR][c]);FORU(i, k+1, N-1){

A[i][k] /= A[k][k];FORU(j, k+1, N-1) A[i][j] -= A[i][k] * A[k][j];

}}return mt(P, L, U);

}

// Finds x such that A * x = Bvd LUP_resolution(LUP const& lup , vd B) {

lli N = X(lup).size ();vd X(N), Y(N);FOR(i, N)

Y[i] = b[X(lup)[i]] - inner_product(Y.data(), Y.data() + i, Y(lup)[i], 0.);FORD(i, N-1, 0)

X[i] = (Y[i] - inner_product( X.data() + i + 1, X.data() + N, Z(lup)[i] + i + 1, 0.)) / Z(lup)[i][i];

}

double LUP_determinant(LUP const& lup){double r = 0;FOR(i, X(lup).size ()) r += Z(lup)[i][i];return r;

}

Simplex — worst case O(2N )

using DOUBLE = long double;using vd = vector <DOUBLE >;using vvd = vector <vd >;const DOUBLE EPS = 1e-9;

struct LPSolver {int m, n;vi N, B;vvd D;

LPSolver(const vvd &A, const vd &b, const vd &c) :m(b.size()), n(c.size()), N(n + 1), B(m), D(m + 2, vd(n + 2)) {for (int i = 0; i < m; i++)

for (int j = 0; j < n; j++) D[i][j] = A[i][j];for (int i = 0; i < m; i++)

{ B[i] = n + i; D[i][n] = -1; D[i][n + 1] = b[i]; }for (int j = 0; j < n; j++)

{ N[j] = j; D[m][j] = -c[j]; }

ENS Ulm 1 École Normale Supérieure ULM 12 of 24

N[n] = -1; D[m + 1][n] = 1;}

void Pivot(int r, int s) {DOUBLE inv = 1.0 / D[r][s];{ vector <tuple <int ,DOUBLE > > L,R;

for (int i = 0; i < m + 2; i++) if (i != r && abs(D[i][s]) > EPS) {L.pb(mt(i,D[i][s]));

}for (int j = 0; j < n + 2; j++) if (j != s && abs(D[r][j]) > EPS) {

R.pb(mt(j,D[r][j]));}

for(auto i : L) for(auto j : R) {D[X(i)][X(j)] -= Y(i) * Y(j) * inv;

}}// the previous block is a (usually) more efficient version of~:// for (int i = 0; i < m + 2; i++) if (i != r)// for (int j = 0; j < n + 2; j++) if (j != s)// D[i][j] -= D[r][j] * D[i][s] * inv;for (int j = 0; j < n + 2; j++) if (j != s) D[r][j] *= inv;for (int i = 0; i < m + 2; i++) if (i != r) D[i][s] *= -inv;D[r][s] = inv;swap(B[r], N[s]);

}

bool Simplex(int phase) {int x = phase == 1 ? m + 1 : m;while (true) {

int s = -1;for (int j = 0; j <= n; j++) {

if (phase == 2 && N[j] == -1) continue;if (s == -1 || D[x][j] < D[x][s] ||

(D[x][j] == D[x][s] && N[j] < N[s])) s = j;}if (D[x][s] > -EPS) return true;int r = -1;for (int i = 0; i < m; i++) {

if (D[i][s] < EPS) continue;if (r == -1 || D[i][n + 1] / D[i][s] < D[r][n + 1] / D[r][s] ||

((D[i][n + 1] / D[i][s]) == (D[r][n + 1] / D[r][s]) &&B[i] < B[r])) r = i;

}if (r == -1) return false;Pivot(r, s);

}}

DOUBLE Solve(vd &x) {int r = 0;for (int i = 1; i < m; i++) if (D[i][n + 1] < D[r][n + 1]) r = i;if (D[r][n + 1] < -EPS) {

Pivot(r, n);if (! Simplex (1) || D[m + 1][n + 1] < -EPS)

return -numeric_limits <DOUBLE >:: infinity ();for (int i = 0; i < m; i++) if (B[i] == -1) {

int s = -1;for (int j = 0; j <= n; j++)

if (s == -1 || D[i][j] < D[i][s] ||(D[i][j] == D[i][s] && N[j] < N[s])) s = j;

Pivot(i, s);}

}if (! Simplex (2)) return numeric_limits <DOUBLE >:: infinity ();x = vd(n);for (int i = 0; i < m; i++) if (B[i] < n) x[B[i]] = D[i][n + 1];return D[m][n + 1];

}};

GeometryPick’s theorem: A = I + 1

2B − 1. (A area polygon, I number of interior points, B number of boundary

points).

Triangle geometryp = a+b+c

2.

Area: A = sinαa

=√p(p− a)(p− b)(p− c).

Incircle: r = Ap. I = a

2pA+ b

2pB + c

2pC.

Length of the angle bissector through A: ia = 2b+c

√p(p− a)bc.

Circumcircle: R = abc4A

= a2 sinα

. O = 1sin(2α)+sin(2β)+sin(2γ)

(sin(2α)A+ sin(2β)B + sin(2γ)C).

Orthocenter: H = 1tanα+tan β+tan γ

(tan(α)A+ tan(β)B + tan(γ)C).Law of cosines: c2 = a2 + b2 − 2ab cos(γ).

Primitives

using pt = complex <lli >;#define xx real()#define yy imag()

lli dot(pt const& a, pt const& b) {return a.xx*b.xx + a.yy*b.yy;

}

lli dot(pt const& a, pt const& b, pt const& c) {return dot(b-a,c-a);

}

// det(pt(1,0), pt(0 ,1)) = 1 (counter clockwise = positive)lli det(pt const& a, pt const& b) {

return a.xx*b.yy - a.yy*b.xx;}

lli det(pt const& a, pt const& b, pt const& c) {return det(b-a,c-a);

}

lli sgn(lli a){if(a<0) return -1;

ENS Ulm 1 École Normale Supérieure ULM 13 of 24

if(a>0) return 1;return 0;

}

lli sdet(pt const& a, pt const& b) {return sgn(a.xx*b.yy - a.yy*b.xx);

}

lli sdet(pt const& a, pt const& b, pt const& c) {return sdet(b-a,c-a);

}

bool segSegInterStrict(pt a1, pt a2, pt b1, pt b2) {return sdet(a1 ,a2,b1)*sdet(a1,a2,b2) < 0 && sdet(b1,b2,a1)*sdet(b1,b2 ,a2) < 0;

}

// !!! Probably wrong !!!

// bool angle_cmp(pt const& uv, pt const& da, pt const& db) {// auto detb = sdet(uv,db);// if (detb == 0 && dot(db,uv) >= 0) return false;// auto deta = sdet(uv,da);// if (deta == 0 && dot(da,uv) >= 0) return true;// if (deta * detb >= 0) {// return sdet(da,db) > 0;// }// return deta > 0;// }

// bool angle_cmp(pt const& u, pt const& v, pt const& a, pt const& b) {// return angle_cmp(v-u,a-u,b-u);// }

complex <long double > conv(pt const& a) {return complex <long double >(a.xx,a.yy);

}

long double lineLineInter(pt const& A, pt const& B, pt const& P, pt const& Q) {lli tr_area = det(A, P, Q);lli quad_area = det(A, P, B) + det(A, B, Q);if (abs(quad_area) == 0) {

assert (0); // No intersection}// return A + (B - A) * (tr_area / quad_area)return (long double)tr_area / (long double)quad_area;

}

Convex hull 2D (Graham scan) — O(N logN)

void add_point(vector <pt> &s, int sign , pt p) {while(s.size() >= 2 &&

det ((*(s.end()-2))-s.back(), p-s.back ())* sign >= 0){s.pop_back ();

}s.push_back(p);

}

vector <pt > convex_hull(vector <pt> const& A){if (N <= 2) return A;vector <pt > c[2];sort(A.begin(), A.end ());FOR(i, 2) for(pt p : A) add_point(c[i], 2 * i - 1, p);c[0]. insert(c[0]. end(), c[1]. rbegin () + 1, c[1]. rend() - 1);return c[0];

}

KdTree — construction O(N logN), nearest neighbor O(√N)

// KdTree building & nearest neighbor routine (needs the pt structure)bool compareX(const pt &u, const pt &v) { return u.x < v.x; }bool compareY(const pt &u, const pt &v) { return u.y < v.y; }struct KdTree {

pt vertex;KdTree *left , *right;KdTree(const pt &p) : vertex(p), left(0), right (0) {}~KdTree () { if (left) delete left; if (right) delete right; }// Build a balanced tree , complexity O(n*log(n))// Use: KdTree * tree = KdTree ::build(myvector.begin(),myvector.size ())typedef vector <pt >:: iterator MyIterator;static KdTree * build(MyIterator first , int n, bool odd = false) {

if (n == 0) return 0;if (n == 1) return new KdTree (*first );nth_element(first , first + n / 2, first + n, (odd ? compareY : compareX ));KdTree *node = new KdTree (*( first + (n / 2)));node ->left = build(first , n / 2, not odd);node ->right = build(first + n / 2 + 1, n - (n / 2) - 1, not odd);return node;

}// Find nearest neighbor , complexity O(n^(1/2))// The returned point (best) is not equal to target (ie not within EPS)// but you can modify the first line to change this behavior// Important: start with a value of radius == numeric_limits <elem >:: max();// Use: tree ->find(target ,best ,radius) input:target result:best ,radiusvoid find(const pt &target , pt &best , double &radius , bool odd = false) {

if (dist2(target ,vertex) > EPS && dist2(target ,vertex) < radius)best = vertex , radius = dist2(target ,vertex );

double dist = odd ? (target - vertex ).y : (target - vertex ).x;double distSquared = dist * dist;if (dist < 0) {

if (left) left ->find(target , best , radius , not odd);if (right && distSquared <= radius)

right ->find(target , best , radius , not odd);} else {

if (right) right ->find(target , best , radius , not odd);if (left && distSquared <= radius)

left ->find(target , best , radius , not odd);}

}};

GraphsStrongly connected components — O(V + E)

ENS Ulm 1 École Normale Supérieure ULM 14 of 24

// input : graph G// output : components cs, colors C, condensed graph G_

void scc(vvi const& G, vvi& cs, vi& C, vvi &G_) {// initializeint n = G.size ();vvi G2(n); FOR(i, n) for(int j : G[i]) G2[j].pb(i);cs.clear (); C.assign(n, -1);vi A;vi E(n);

function <void(int)> dfs = [&]( int i) {if(E[i]) return;E[i] = 1;for(int j : G[i]) dfs(j);A.pb(i);

};FOR(i, n) dfs(i);reverse(all(A));

function <void(int , int)> dfs2 = [&]( int i, int r) {if(C[i] == -1) {

cs.back ().pb(i); C[i] = r;for(int j : G2[i]) dfs2(j, r);

}};for(int i : A) if(C[i] == -1) { cs.pb(vi{}); dfs2(i, cs.size ()-1); }

G_.assign(n, vi{});unordered_set <pii > M;FOR(i, n) for(int j : G[i]) M.insert(mt(C[i], C[j]));for(pii p : M) if(p.x() != p.y()) G_[p.x()].pb(p.y());

}

2-sat

vi sat2(int n, vii const& A){vvi G(2*n);for(auto p : A) {

int u,v; tie(u,v) = p;G[u].pb(v+1);G[v].pb(u+1);

}vvi cs;vi C;scc(G,cs,C);FOR(i,n) if(C[2*i] == C[2*i+1]) return vi(); // UNSATvi ans(n,-1);reverse(all(cs));for(auto const& c : cs) {

if(ans[c[0]>>1] != -1) continue;for(lli u : c) ans[u>>1] = (u&1);

}return ans;

}

Centroid decomposition — O(V log V )

// centroid decomposition// input : tree Gvoid centroid_decomposition(vvi const& G) {

int n = G.size ();vi A(n,0);vi CP(n,-1);int root;FOR(l ,100){

vi E = A;vi P(n);vi S(n,1);function <void(vi&, int ,int)> dfs0 = [&](vi& C, int i,int p){

E[i]=1; P[i]=p; C.pb(i);for(int j : G[i]) if(!A[j] && j!=p) {

dfs0(C,j,i);S[i]+=S[j];

}};vi C;FOR(i,n) if(!E[i]) {

C.clear ();dfs0(C, i, -1);auto f = [&]( int j){

int r=0;for(auto k : G[j]) if(!A[k] && k!=P[j]) r=max <int >(r,S[k]);r=max <int >(r,S[i]-S[j]);return r;

};int centroid=i; int best=f(i);for(int j : C) {

int v=f(j); if(v<best) { centroid=j; best=v; }}A[centroid ]=1;// do a dfs on this centroid subtree here :// doDfs(centroid );if(CP[centroid ]==-1) root=centroid;for(int j : C) if(j!= centroid) CP[j]= centroid;

}FOR(i,n) if(!A[i]) goto l_beg;break;

l_beg :;}

vvi H(n); FOR(i,n) if(CP[i]!= -1) H[CP[i]].pb(i);// the tree (root ,H) is now a centroid decomposition

}

ENS Ulm 1 École Normale Supérieure ULM 15 of 24

Minimum average cycle — O(V E)

Noeud essentiels — O(E)

Bridges (Arcs essentiels) — O(E)

Dominator tree — O((V + E) log V )

// dominator : u dominates v if any path s..v goes through u// idom[v] : the unique dominator of v dominated by all other dominatorsnamespace dtree {

const int MAXN = 1e6+16;vector <int > E[MAXN], RE[MAXN], rdom[MAXN];

int S[MAXN], RS[MAXN], cs;int par[MAXN], val[MAXN], sdom[MAXN], rp[MAXN], dom[MAXN];

void reset(int n) {cs = 0;FOR(i,n+16) {

par[i] = val[i] = sdom[i] = rp[i] = dom[i] = S[i] = RS[i] = 0;E[i]. clear (); RE[i].clear (); rdom[i]. clear ();

}}

void add_edge(int x, int y) { E[x]. push_back(y); }void unite(int x, int y) { par[x] = y; }int find(int x, int c = 0) {

if(par[x] == x) return c ? -1 : x;int p = find(par[x], 1);if(p == -1) return c ? par[x] : val[x];if(sdom[val[x]] > sdom[val[par[x]]]) val[x] = val[par[x]];par[x] = p;return c ? p : val[x];

}

void dfs(int x) {RS[ S[x] = ++cs ] = x;par[cs] = sdom[cs] = val[cs] = cs;for(int e : E[x]) {

if(S[e] == 0) dfs(e), rp[S[e]] = S[x];RE[S[e]]. push_back(S[x]);

}}

// Call reset(n) after solve !!!int solve(int s, int* idom) { // Calculate idoms

dfs(s); idom[s] = -1;FORD(i,cs ,1) {

for(int e : RE[i]) sdom[i] = min(sdom[i], sdom[find(e)]);if(i > 1) rdom[sdom[i]]. push_back(i);for(int e : rdom[i]) {

int p = find(e);if(sdom[p] == i) dom[e] = i;else dom[e] = p;

}if(i > 1) unite(i, rp[i]);

}FORU(i,2,cs) if(sdom[i] != dom[i]) dom[i] = dom[dom[i]];FORU(i,2,cs) idom[RS[i]] = RS[dom[i]];return cs;

}}// Usage:// for(auto [x,y] : edges) dtree :: add_edge(x,y);// int idom[N];// FOR(i,n) idom[i] = -1;// dtree::solve(source , idom);// dtree::reset(n);// vvi G(n);// FOR(i,n) if(idom[i] != -1) G[idom[i]].pb(i);// G is now the dominator tree , u dominates v when it is an ancestor :)

Matching in general graph — O(V 3)

const int MAX_V = 2001;int V; // Entree : Nombre de sommetsvi adj[MAX_V]; // Entree : Listes d’adjacenceint mu[MAX_V]; // Sortie : (v,mu[v]) est le matching recherche

// v == mu[v] si v n’est pas dans la matchingint phi[MAX_V];int rho[MAX_V];bool scanned[MAX_V];int found[MAX_V];

bool IsOuter(int x) {return mu[x] == x || phi[mu[x]] != mu[x];

}

int FindPath(int x) {for(int z = x;; z = phi[mu[z]]) {

if(found[z] != -1 && rho[z] == z) {return z;

}found[mu[z]] = 1;found[z] = 0;if(mu[z] == z) break;

}return -1;

}

void MaxMatching () {iota(mu , mu+V, 0);FOR(v, V) FOR(n, (int)adj[v].size ()) {

if(mu[v] == v && mu[adj[v][n]] == adj[v][n]) {mu[mu[v] = adj[v][n]] = v;

}}vi CX;

Phase2:CX.clear ();iota(phi , phi+V, 0);iota(rho , rho+V, 0);

ENS Ulm 1 École Normale Supérieure ULM 16 of 24

FOR(v, V) if(mu[v] == v) {CX.push_back(v);

}fill_n(scanned , V, 0);

while (!CX.empty ()) {int x = CX.back ();CX.pop_back ();if(scanned[x] || !IsOuter(x)) continue;int y;FOR(n, (int)adj[x].size ()) {

y = adj[x][n];if(mu[y] != y && phi[y] == y && phi[mu[y]] == mu[y]) {

phi[y] = x;CX.push_back(mu[y]);

} else if(IsOuter(y) && rho[y] != rho[x]) {fill_n(found ,V,-1);FindPath(x);const int r = FindPath(y);if(r == -1) {

FOR(v, V) if(found[v] == 1) {mu[mu[v] = phi[v]] = v;

}mu[x] = y;mu[y] = x;goto Phase2;

}

if(mu[r] != r) { found[mu[r]] = -1; }for(int z = phi[mu[r]]; found[z] != -1; z = phi[mu[z]]) {

found[z] = found[mu[z]] = -1;}FOR(v, V) if(found[v] == 1 && rho[phi[v]] != r) {

phi[phi[v]] = v;}if(rho[x] != r) { phi[x] = y; }if(rho[y] != r) { phi[y] = x; }FOR(v,V) if(found[rho[v]] != -1) {

rho[v] = r;}FOR(v, V) if(found[v] == 1) {

CX.push_back(v);}

}}scanned[x] = 1;

}}

Hungarian algorithm — O(V 3)

const lli INF = (1ll <<60);const lli N = 2222;

lli a[N][N];

// Returns the minimum cost maximum matching

// !!! !!!// !!! Hangs when n > m !!!// !!! Transpose the matrix if needed !!!// !!! !!!lli hungarian(lli n, lli m) {

assert(n <= m);vi u(n + 1), v(m + 1), p(m + 1), way(m + 1);FORU(i,1,n) {

p[0] = i;lli j0 = 0;vi minv(m + 1, INF);vi used(m + 1, false);do {

used[j0] = true;lli i0 = p[j0], delta = INF , j1;FORU(j,1,m) if(!used[j]) {

lli cur = a[i0][j] - u[i0] - v[j];if(cur < minv[j]) { minv[j] = cur; way[j] = j0; }if(minv[j] < delta) { delta = minv[j]; j1 = j; }

}FORU(j,0,m) {

if(used[j]) { u[p[j]] += delta; v[j] -= delta; }else { minv[j] -= delta; }

}j0 = j1;

} while(p[j0] != 0);do {

lli j1 = way[j0];p[j0] = p[j1];j0 = j1;

} while(j0);}return -v[0];

}

FlowsMin-Cost : si il y a des coûts.Edmonds-Karp : graphe avec des faibles capacités (< 4), matching.Capacity scaling : graphe avec des capacités arbitraires. A utiliser dans la plupart des cas.Dinic : si les deux autres sont trop lents.

// Common Max -Flow structuresstruct edge {

edge(lli to_ , lli c_, lli cost_) : to(to_), c(c_), f(0), cost(cost_){ }lli to;lli c; // capacitylli f; // current flowlli cost; // Only used in a Min -Cost Max -Flow algorithmedge* rev;

};

using graph = vector <vector <edge*>>;

edge* add_edge(graph& G, lli a, lli b, lli c, lli cost = 0){edge* e1 = new edge(b, c, cost);

ENS Ulm 1 École Normale Supérieure ULM 17 of 24

edge* e2 = new edge(a, 0, -cost);e1->rev = e2;e2->rev = e1;G[a].pb(e1);G[b].pb(e2);return e1;

}

Max flow, Capacity scaling — O(E2 logF )

// Computes a maximum flow in G// Returns the modification of the flow// S : source , T : targetlli flow_scaling(graph& G, lli S, lli T){

lli N = G.size ();vi E;function <bool(lli , lli)> dfs = [&]( lli i, lli f) -> bool {

if(i == T) return true;if(!E[i]) return false;E[i] = true;for(edge* e : G[i]) if(e->c - e->f > f && dfs(e->to, f)){

e->f += f;e->rev ->f -= f;return true;

}return false;

};lli df = 0; // Delta flowlli f = (1<<62);while(f > 0){

E.assign(N, false); // Can be a bottleneckif(dfs(S)) df += f;else f /= 2;

}return df;

}

Max flow, Dinic — O(V 2E)

lli flow(graph& G, lli S, lli T){lli N = G.size ();lli f = 0;vi D, W;while (1){

// bfsD.assign(N, -1);queue <lli > Q; Q.push(S); D[S] = 0;while (!Q.empty ()){

lli i = Q.front (); Q.pop();if(i == T) break; // uncheckedfor(edge *e : G[i]) if(e->c > e->f && D[e->to] == -1){

D[e->to] = D[i] + 1;Q.push(e->to);

}

}if(D[T] == -1) return f;// dfsW.assign(N, 0);function <lli(lli , lli)> dfs = [&]( lli i, lli f){

if(i == T) return f;lli cf = 0;for(; W[i] < (lli)G[i].size (); W[i]++) {

edge *e = G[i][W[i]];if(e->c > e->f && D[e->to] == D[i] + 1){

lli df = dfs(e->to, min(f, e->c - e->f));if(df > 0){

cf += df;f -= df;e->f += df;e->rev ->f -= df;

}}

}return cf;

};while(lli df = dfs(S, infinity )) f += df;

}return f;

}

Min-cost Max-flow

void flow(graph &G, lli S, lli T){lli n = G.size ();

lli f = 0, r = 0;

vi E, C;vector <edge*> F;while (1){

E.assign(n, -1); F.assign(n, nullptr ); C.assign(n, -1);min_queue <pii > Q; C[S] = 1e15; E[S] = 0; Q.push(mt(0, S));while (!Q.empty ()){

DESTRUCT2(Q.top(), d, i); Q.pop();if(d == E[i]){

for(edge* e : G[i]) {if(e->c - e->f > 0 && (E[e->to] == -1 || E[i]+e->cost < E[e->to])){

E[e->to] = E[i] + e->cost;F[e->to] = e;if(C[e->to] == -1) C[e->to] = e->c - e->f;C[e->to] = min(C[e->to], min(e->c - e->f, C[i]));Q.push(mt(E[e->to], e->to));

}}

}}if(F[T] == 0) break;else {

edge* e = F[T];f += C[T];

ENS Ulm 1 École Normale Supérieure ULM 18 of 24

while(e != 0){e->f += C[T];e->rev ->f -= C[T];r += C[T] * e->cost;e = F[e->rev ->to];

}}

}

// FLOW = f, COST = r}

Minimum cut construction from a maximum flow

vector <edge*> get_minimum_cut(graph& G, lli S){int n=G.size ();vi E(n);function <void(int)> dfs = [&]( int i){

if(E[i]) return;E[i]=1;for(edge* e : G[i]) if(e->f < e->c) dfs(e->to);

};dfs(S);vector <edge*> R;FOR(i,n) if(E[i]) for(edge* e : G[i]) if(!E[e->to]) R.pb(e);return R;

}

String, languages

Z Function — O(M +N)

// Z[i]= length of longest sustring starting at S[i] which is also a prefix of S

vi zfunction(vi const& S){vi Z(S.size ());lli L = 0, R = 0;FORU(i, 1, S.size ()-1){

if(i > R){L = R = i;while(R < n && S[R-L] == S[R]) R += 1;

}else{lli k = i - L;if(Z[k] < R-i+1) Z[i] = Z[k];else {

L = i;while(R < n && S[R-L] == S[R]) R += 1;Z[i] = R-L; R--;

}}

}}

KMP — O(M +N)

// T[i+1] = length of longest substring ending at S[i]

// that is also a prefix of S[0..i-1]

vi kmp_build(vi const& s){int n = s.size ();vi T(n+1);T[0] = -1;FOR(i, n) {

int b = T[i];while(b != -1 && s[i] != s[b]) b = T[b];T[i+1] = b+1;

}return T;

}

int kmp_next(vi const& s, vi const& T, int i, int x){while(i != -1 && x != s[i]) i = T[i];return i+1;

}

vi occurences(vi const& T, vi const& A) {lli S = 0;vi R;FOR(i, A.size ()){

S = kmp_next(T, S, A[i]);if(S == T.size ()-1) R.pb(i);

}return R;

}

Aho Corasick — O(M +N)

struct node {unordered_map <lli , lli > nexts;lli back;unordered_set <lli > ends;

};

vector <node > aho_build(vvi const& W){vector <node > T; T.pb(node ());FOR(i, W.size ()){

lli n = 0;for(lli c : W[i]){

if(T[n]. nexts.count(c) == 0){T[n]. nexts[c] = T.size ();T.pb(node ());

}n = T[n]. nexts[c];

}T[n].ends.insert(i);

}// ---queue <lli > q; q.push (0);T[0]. back = -1;while (!q.empty ()){

lli n = q.front (); q.pop();// Remove this line if only the largest match at each position is neededif(T[n].back != -1) for(auto i : T[T[n].back].ends) T[n].ends.insert(i);

ENS Ulm 1 École Normale Supérieure ULM 19 of 24

// ---for(auto p : T[n]. nexts){

lli b = T[n].back;while(b != -1 && T[b]. nexts.count(p.first) == 0)

b = T[b].back;T[p.second ].back = (b== -1)?0:T[b].nexts[p.first ];q.push(p.second );

}}return T;

}

lli aho_next(vector <node >& T, lli S, lli x){while(S != -1 && T[S]. nexts.count(x) == 0) S = T[S].back;return (S== -1)?0:T[S].nexts[x];

}

void occurences(vector <node >& T, vi const& A) {int S = 0;FOR(i, A.size ()){

S = aho_next(T, S, A[i]);for(auto p : T[S].ends){

cout << i << "␣" << p << endl;}

}}

Suffix array — O(N(logN)2), fast

// sa : suffix array// isa : inverse suffix array// pos , tmp : only used for the computation// lcp : length of common prefix arraystruct SA {

string &S;int N;vi sa , isa , pos , tmp , lcp;

SA(string &S_) : S(S_), N(S_.size()), sa(N), pos(N+1), tmp(N+1), lcp(N) {FOR(i, N) sa[i] = i, pos[i] = S[i];for(int gap = 1;; gap *= 2) {

auto sufCmp = [&]( int i, int j) {if(pos[i] != pos[j]) return pos[i] < pos[j];i += gap;j += gap;return (i<N && j<N) ? pos[i]<pos[j] : i>j;

};sort(all(sa), sufCmp );FOR(i, N-1) tmp[i+1] = tmp[i] + sufCmp(sa[i], sa[i+1]);FOR(i, N) pos[sa[i]] = tmp[i];if(tmp[N-1] == N-1) break;

}isa.resize(N);FOR(i, N) isa[sa[i]] = i;for(int i = 0, k = 0; i < N; ++i) if(pos[i] != N-1) {

for(int j = sa[pos[i]+1];i+k<N && j+k<N && S[i+k] == S[j+k];) k += 1;

lcp[pos[i]] = k;if(k) k -= 1;

}}

};

O(1) RMQ queries — fast O(N logN) precomputation

const int N = 1e5;const int LN = 20; // > log(N)pair <int ,int > RMQ[LN][N];int ilog2(int x){ return 31 - __builtin_clz(x); }

// Pre: RMQ [0][i].first is set to the initial arrayvoid calc(int n){

FOR(i,n) RMQ [0][i]. second = i;FOR(i,LN -1) FOR(j,n) {

if(j+(1<<(i+1))<=n) {RMQ[i+1][j] = min(RMQ[i][j], RMQ[i][j+(1<<i)]);

}}

}

pair <int ,int > query(int l, int r) {int sz = ilog2(r-l+1);if(RMQ[sz][l] <= RMQ[sz][r-(1<<sz)+1]) {

return RMQ[sz][l];}else{

return RMQ[sz][r-(1<<sz)+1];}

}

Suffix tree from a suffix array

// Pre : compute the suffix array , the lcp array ,// and the O(1) rmq array on the lcp array// rmq_query(l,r) returns a pair (minimum value , index)// with (l <= index && index <= r)// !!!// !!! index must be the first reached minimum// !!!function <void(int ,int ,int)> make_tree = [&]( int l, int r, int sz) {

if(l == r) {return; // Leaf

}int v = rmq_query(l,r-1). first; // The lcp of this rangeint last = l;// Compute all splitting positions in the segmentwhile(last < r) {

auto p = rmq_query(last ,r-1);if(p.first != v) break;make_tree(last ,p.second ,v);last = p.first +1;

}make_tree(last ,r,v);

};

ENS Ulm 1 École Normale Supérieure ULM 20 of 24

make_tree(0,n-1,0);

Suffix automaton

const int N = 1; // "CHANGE ME"struct SuffixAutomaton {

int edges [26][2*N+1], link [2*N+1], length [2*N+1], isTerminal [2*N+1], last;int sz;

void set(int k) {FOR(i,26) edges[i][k] = -1;

}

void build(char *s, int size) {link [0] = -1; length [0] = 0; last = 0; sz = 1;set (0);

FOR(i,size) {set(sz); length[sz] = i+1; link[sz] = 0;int r = sz;sz += 1;

int p = last;while(p >= 0 && edges[s[i]-’a’][p] == -1) {

edges[s[i] - ’a’][p] = r;p = link[p];

}if(p != -1) {

int q = edges[s[i] - ’a’][p];if(length[p] + 1 == length[q]) {

link[r] = q;} else {

for(int i = 0; i < 26; ++i) {edges[i][sz] = edges[i][q];

}length[sz] = length[p] + 1;link[sz] = link[q];int qq = sz;sz += 1;link[q] = qq;link[r] = qq;while(p >= 0 && edges[s[i] - ’a’][p] == q) {

edges[s[i] - ’a’][p] = qq;p = link[p];

}}

}last = r;

}FOR(i,sz) isTerminal[i] = 0;int p = last;while(p > 0) {

isTerminal[p] = 1;p = link[p];

}}

int next(int s, char x) {if(s == -1) return -1;return edges[x-’a’][s];

}};

Palindromic tree — O(N)

const int N = 1e6+3;

map <int ,int > to[N]; // Childrenint link[N]; // Parentint diff[N]; // Length difference with the parentint slink[N]; // Link to the first parent of a different series

// A series is a sequence of palindrome with constant size difference// The path to the root through slink has size O(log n)

int len[N]; // Node palindrome lengthint last[N]; // Nodes of prefixes of sint n, m; // String size , tree sizeint s[N]; // String

void init() {link [0] = link [1] = 0;last [0] = 0;len [0] = -1; len[1] = 0;diff [0] = diff [1] = -1;slink [0] = slink [1] = -1;n = 0; m = 2;

}

void add(int x) {s[n] = x; n += 1;last[n] = last[n-1];while(s[n-2-len[last[n]]] != x) last[n] = link[last[n]];if(!to[last[n]]. count(x)) {

int v = m; m++;to[last[n]][x] = v;len[v] = len[last[n]]+2;if(len[v] == 1) {

link[v] = 1;} else {

link[v] = link[last[n]];while(s[n-2-len[link[v]]] != x) link[v] = link[link[v]];link[v] = to[link[v]][x];

}diff[v] = len[v] - len[link[v]];if(diff[v] == diff[link[v]]) {

slink[v] = slink[link[v]];}else{

slink[v] = link[v];}last[n] = v;

}else{last[n] = to[last[n]][x];

}}

ENS Ulm 1 École Normale Supérieure ULM 21 of 24

Useless stuffMax clique

struct max_clique {int n;vector <vector <unsigned char >> adj;

vector <vector <int >> es;vector <vector <tpl <int ,int > > > vs;

struct vertex {vertex () = default;vertex(int id_) {

id = id_;}

int id, bound;};

vector <vector <vertex >> P;vector <int > level;

vector <int > colors;vector <vector <vertex >> colorVertices;vector <int > vertexColor;vector <int > vertexExplored;

vector <int > maxClique;

max_clique(vector <vector <int >> G) {maxClique = {0}; // Initialize with a size 1 clique

n = G.size ();adj.assign(n, vector <unsigned char >(n,0));FOR(i,n) for(int j : G[i]) adj[i][j] = 1;

es.resize (1); vs.resize (1); vs[0]. resize(n);

FOR(i,n) {vs[0][i].x() = es[0]. size ();FOR(j,n) {

if(adj[i][j]) {es[0]. emplace_back(j);

}}vs[0][i].y() = es[0]. size ();

}

P.resize (2);level.assign(n,0);

colors.assign(n+3,0);colorVertices.resize(n+3);vertexColor.assign(n,0);vertexExplored.assign(n,0);

}

void induce(vector <int > const& s) {int sz = s.size ();if((int)es.size() == sz) {

es.emplace_back ();vs.emplace_back(n);

}auto const& Pcur = P[sz];auto const& esPrev = es[sz -1];auto const& vsPrev = vs[sz -1];auto& esCur = es[sz];auto& vsCur = vs[sz];

esCur.clear ();FOR(w,Pcur.size ()) {

int i = Pcur[w].id;vsCur[i].x() = esCur.size ();int from = vsPrev[i].x(), to = vsPrev[i].y()-1;FORU(ei ,from ,to) {

auto const& e = esPrev[ei];if(level[e] == sz) {

esCur.pb(e);}

}vsCur[i].y() = esCur.size ();

}}

void color(vector <int > const& s){int sz = s.size ();int max_k = 1;colors [1] = colors [2] = 0;int date = 0;

FOR(w, P[sz].size ()) {int i = P[sz][w].id;date += 1;int from = vs[sz][i].x(), to = vs[sz][i].y()-1;

if(sz+1+(to-from +1) < (int)maxClique.size ()+1) {level[i]--;

}else{FORU(jk,from ,to) if(vertexExplored[es[sz][jk]]) {

colors[vertexColor[es[sz][jk]]] = date;}

int k = 1; while(colors[k] == date) k += 1;if(k > max_k) { max_k += 1; colors[max_k +1] = 0; }vertexExplored[i] = 1; vertexColor[i] = k;colorVertices[k].pb(P[sz][w]);

}}

P[sz].clear ();FORU(k,1,max_k) {

for(auto const& v : colorVertices[k]) {

ENS Ulm 1 École Normale Supérieure ULM 22 of 24

vertexExplored[v.id] = 0;P[sz].pb(v);P[sz].back (). bound = k;

}colorVertices[k].clear ();

}}

void searchAt(int i) {vector <int > s; s.pb(i);FOR(j,i) if(adj[i][j]) {

level[j]++;P[1].pb(vertex { (int)j });

}induce(s);color(s);branch(s);

}

void search (){FOR(i,n) searchAt(i);

}

void branch(vector <int > const& s){int sz = s.size ();while (!P[sz].empty () && sz + P[sz].size() >= (maxClique.size ()+1)) {

vertex v = P[sz].back ();

level[v.id]--;P[sz]. pop_back ();

if((int)P.size() == sz+1) P.emplace_back ();

if(sz + v.bound <= (int)maxClique.size ()) continue;for(auto const& w : P[sz]) if(adj[v.id][w.id]) {

level[w.id]++;P[sz+1]. emplace_back(w);

}vector <int > s2 = s; s2.pb(v.id);if(sz+1 > (int)maxClique.size ()) maxClique = s2;induce(s2);color(s2);if(!P[sz+1]. empty ()) branch(s2);

}while (!P[sz].empty ()) {

vertex const& v = P[sz].back ();level[v.id]--;P[sz]. pop_back ();

}}

};

// Usage:// max_clique mc(G);// mc.search ();// C = mc.maxClique

Graph isomorphism

struct WLGIso {// staticvvi G[2];int n;vi ghashes;

// dynamicint partitionSize = 0;vvi partition [2];vi color [2];vi hash [2];

vi inQ;vi Q;

vector <tuple <int , vector <tuple <int ,array <vi ,2>>>>> history;

WLGIso(vvi G1, vvi G2) {G[0] = G1; G[1] = G2;n = G1.size ();assert(n == (int)G2.size ());ghashes.resize (2*n);FOR(i,2*n) ghashes[i] = rand ()* rand ()+ rand ();FOR(ix ,2) {

color[ix]. resize(n);hash[ix]. assign(n,0ll);

}// Initialize the partition{ unordered_map <int , array <vi ,2>> dPartition;

FOR(ix ,2) FOR(i,n) dPartition[G[ix][i].size ()][ix].pb(i);for(auto const& p : dPartition) {

array <vi ,2> const& v = p.second;assert(v[0]. size() == v[1]. size ());FOR(ix ,2) {

partition[ix]. emplace_back ();for(int i : v[ix]) {

partition[ix].back ().pb(i);color[ix][i] = partitionSize;

}}inQ.pb(1); Q.pb(partitionSize ); partitionSize ++;

}}// Initialize the hashesFOR(ix ,2) FOR(i,n) for(int j : G[ix][i]) {

hash[ix][i] += ghashes[color[ix][j]];}

history.emplace_back (); X(history.back ()) = partitionSize;}

void push(int i) {if(partition [0][i].size() > 1 && !inQ[i]) {

inQ[i]=1;

ENS Ulm 1 École Normale Supérieure ULM 23 of 24

Q.pb(i);}

}

void split(int i, vector <array <vi ,2>> const& w){Y(history.back ()). emplace_back

(i,array <vi ,2>{{ partition [0][i],partition [1][i]}});FOR(ix ,2) for(int j : partition[ix][i]) for(int k : G[ix][j]) {

push(color[ix][k]);hash[ix][k] -= ghashes[i];

}bool first = 1;for(auto const& v : w) {

int pi = first ? i : partitionSize;if(! first) {

FOR(ix ,2) partition[ix]. emplace_back ();inQ.pb(0);partitionSize += 1;

}else{FOR(ix ,2) partition[ix][pi].clear ();

}first = 0;

FOR(ix ,2) for(int j : v[ix]) {partition[ix][pi].pb(j);color[ix][j] = pi;for(int k : G[ix][j]) {

hash[ix][k] += ghashes[pi];}

}push(pi);

}}

bool refine (){while (!Q.empty ()) {

int i = Q.back (); Q.pop_back (); inQ[i]=0;unordered_map <lli , array <vi ,2> > hPart;FOR(ix ,2) for(int j : partition[ix][i]) {

hPart[hash[ix][j]][ix].pb(j);}for(auto const& q : hPart) {

auto const& v = q.second;if(v[0]. size() != v[1]. size ()) return false;

}if(hPart.size() == 1) continue;vector <array <vi ,2>> w;for(auto const& q : hPart) w.pb(q.second );split(i,w);

}return true;

}

void backtrack () {int oldSize = X(history.back ());vector <tuple <int ,array <vi ,2>>>& v = Y(history.back ());

FOR(ix ,2) while((lli)partition[ix].size() > oldSize) {int pi = partition[ix].size() - 1;for(int i : partition[ix].back ()) for(int j : G[ix][i]) {

hash[ix][j] -= ghashes[pi];}partition[ix]. pop_back ();

}while (!v.empty ()) {

int i = X(v.back ());array <vi ,2> const& w = Y(v.back ());if(i<oldSize) {

FOR(ix ,2) {for(int j : partition[ix][i]) for(int k : G[ix][j]) {

hash[ix][k] -= ghashes[i];}

partition[ix][i] = w[ix];for(int j : partition[ix][i]) {

color[ix][j] = i;for(int k : G[ix][j]) {

hash[ix][k] += ghashes[i];}

}}

}v.pop_back ();

}partitionSize = oldSize;inQ.resize(oldSize );history.pop_back ();

}

bool run(int i){history.emplace_back (); X(history.back ()) = partitionSize;if(! refine ()) {

backtrack ();return 0;

}

while(i<partitionSize && partition [0][i].size() == 1) {i++;

}if(i == partitionSize) return 1;

FOR(j, (lli)partition [1][i].size ()) {history.emplace_back (); X(history.back ()) = partitionSize;

vector <array <vi ,2>> w(2);FOR(ix ,2) w[0][ix] = partition[ix][i];swap(w[0][1][j],w[0][1]. back ());FOR(ix ,2) {

w[1][ix].pb(w[0][ix].back ());w[0][ix]. pop_back ();

}

split(i, w);if(run(i)) return 1;

ENS Ulm 1 École Normale Supérieure ULM 24 of 24

backtrack ();}

backtrack ();return 0;

}};

Gomory Hu (all mincuts in an undirected graph) — O(N ∗ flow)

vii gomory_hu(vvii const& g){int n = g.size ();vii R(n,pii (0 ,0));FORU(i,1,n-1) {

MaxFlow F(n);FOR(a,n) for(auto e : g[a]) F.addEdge(a,X(e),Y(e));X(R[i]) = F.flow(i, Y(R[i]));

vi E(n,0);function <void(int)> dfs = [&]( int i) {

if(E[i]) return;E[i] = 1;for(auto e : F.G[i]) if(e->f < e->c) dfs(e->to);

};dfs(i);FORU(j,i+1,n-1) {

if(Y(R[j]) == Y(R[i]) && E[j]) Y(R[j]) = i;}

}return R;

}

// Usage:// auto P = gomory_hu(G);// lli F[200][200];// FOR(i,n) FOR(j,n) F[i][j] = -1;// function <lli(int ,int)> getF = [&]( int i, int j) -> lli {// if(F[i][j] != -1) return F[i][j];// if(i == j) return F[i][j] = (1ll <<50);// if(i) F[i][j] = max(F[i][j], min(getF(Y(P[i]), j), X(P[i])));// if(j) F[i][j] = max(F[i][j], min(getF(i, Y(P[j])), X(P[j]));// return F[i][j];// };