Notebook
Notebook
mas[top++] = cur;
const int N = 100007; }
1 Dynamic Programming 1 const LD eps = 1e-9; /*
1.1 Convex Hull Trick . . . . . . . . . . . . . . . 1 struct Line { // O(logN) general case
1.2 ConvexHull Hull Trick (Integers) . . . . . . . . . 1 LD a, b; long long get(long long x){
Divide and Conquer Optimization . . . . . . . . . Line(LD a = 0.0, LD b = 0.0) : a(a), b(b) {} if (top == 0) return INF;
1.3 1
bool operator < (const Line &o) const { int ina=0,inb=top-1,answ;
1.4 Knuth Optimization (Type 1) . . . . . . . . . . 2 return a > o.a; while(ina<=inb){
1.5 Knuth Optimization (Type 2) . . . . . . . . . . 2 } int mid=(ina+inb)/2;
} st[N], mas[N]; long long p, q;
int top, n; if(mid==0) {
2 Data Structures 2 p = -INF;
2.1 2D Dynamic Segment Tree . . . . . . . . . . . 2 inline LD cross(const Line &u, const Line &v) {
}
q = 1;
2.2 Centroid Decomposition . . . . . . . . . . . . 2
}
return (v.b - u.b) / (u.a - v.a);
else {
2.3 DSU With Rollbacks . . . . . . . . . . . . . . 3 p = mas[mid-1].b - mas[mid].b;
2.4 Heavy-Light Decomposition . . . . . . . . . . . 3 void add(const Line &L) { q = mas[mid].k - mas[mid-1].k;
2.5 Persistent Segment Tree With Range Updates . . . . 3 while (top > 1 && cross(st[top - 2], st[top - 1]) > cross(st[
top - 1], L) - eps) {
}
if((LD)p / q <= x){
2.6 Treap With Implicit Key . . . . . . . . . . . . 4 --top; answ=mid;
2.7 Persistent Treap . . . . . . . . . . . . . . . 4 } ina=mid+1;
2.8 Splay Tree . . . . . . . . . . . . . . . . . . 4 st[top++] = L; }
else
2D Fenwick Tree Range Updates . . . . . . . . . }
2.9 5 inb=mid-1;
LD query(LD x) { }
int l = 0; long long pat=mas[answ].k * x + mas[answ].b;
3 Geometry 5 int r = top - 1; return -pat;
3.1 3D Convex Hull . . . . . . . . . . . . . . . 5 LD lx, rx; }*/
3.2 Closest Point Pair . . . . . . . . . . . . . . . 6 int pos = -1;
Dynamic Upper Convex Hull . . . . . . . . . . . while (true) { // Amortized O(1), if queries are sorted
3.3 6 long long get(long long x){
int m = (l + r) / 2;
3.4 Farthest Point Pair . . . . . . . . . . . . . . 6 LD x1 = -1e18, x2 = 1e18; if (top == 0) return INF;
3.5 Half Plane Intersection (Randomized Incremental Algo- if (m != 0) { pointer = min(pointer , top-1);
x1 = cross(st[m - 1], st[m]); while(pointer < top-1){
rithm) . . . . . . . . . . . . . . . . . . . 7 } long long p,q;
3.6 Minkowski Sum of Convex Polygons . . . . . . . . 7 if (m != top - 1) {
x2 = cross(st[m], st[m + 1]);
q = mas[pointer+1].k - mas[pointer].k;
p = mas[pointer].b - mas[pointer+1].b;
3.7 Pair of Intersecting Segments . . . . . . . . . . 8 } if((LD)p / q <= x)
3.8 Minimum Enclosing Circle (Randomized Incremental Al- if (x > x1 - eps && x < x2 + eps) { ++pointer;
pos = m; else
gorithm) . . . . . . . . . . . . . . . . . . 9 lx = x1; break;
rx = x2; }
break; long long pat=mas[pointer].k * x + mas[pointer].b;
4 Graphs 9 } return -pat;
4.1 Facet Finding . . . . . . . . . . . . . . . . 9 else if (x < x1 - eps) { }
LCA O(1) . . . . . . . . . . . . . . . . . . r = m - 1;
4.2 10 } hull;
}
4.3 Min Cost Max Flow (Dijkstra with Potentials) . . . . 10 else {
4.4 Offline LCA (Tarjan) . . . . . . . . . . . . . 10 l = m + 1;
4.5 Online LCA . . . . . . . . . . . . . . . . . 10 }
}
Rooted Tree Isomorphism . . . . . . . . . . . .
4.6
4.7 Vertex Cover (Types of Vertices) . . . . . . . . .
11
11
assert(pos != -1);
Line &L = st[pos];
1.3 Divide and Conquer Optimization
4.8 Hungarian Algorithm . . . . . . . . . . . . . 11 return L.a * x + L.b;
Cactus . . . . . . . . . . . . . . . . . . . }
4.9 11 // dp[i][j] = min_{k<j}{ dp[i-1][k] + cost(k,j) }
// if opt[i][j] <= opt[i][j+1]
5 Math 12 int dp[N][N];
5.1 Chinese Remainder Theorem . . . . . . . . . . . 12
1.2 ConvexHull Hull Trick (Integers)
5.2 Discrete Logarithm and Square Root . . . . . . . 12 int cost(int l, int r) {
Extended Euclid Algorithm . . . . . . . . . . . // ...
5.3 12
}
5.4 Fast Fourier Transform . . . . . . . . . . . . . 12 struct convex_hull {
5.5 Generator of Zp . . . . . . . . . . . . . . . 12 int top, pointer; void calcdp(int k, int l, int r, int optl, int optr) {
5.6 Linear Time Precalculation of Inverses . . . . . . . 12 if (l > r) return;
struct uxix{
5.7 Simplex Algorithm . . . . . . . . . . . . . . 13 long long k,b; int m = (l+r) / 2;
} mas[N]; int best = INF;
int pos = -1;
6 Strings 13 void init() {
6.1 Aho-Corasick . . . . . . . . . . . . . . . . 13 top = 0; for (int j = optl; j <= min(m, optr); ++j) {
6.2 Discrete Manacer . . . . . . . . . . . . . . . 13 pointer = 0; int val = dp[k-1][j-1] + cost(j, m);
Palindromic Tree . . . . . . . . . . . . . . . } if (val < best) {
6.3 13
best = val;
6.4 Prefix Function . . . . . . . . . . . . . . . . 14 void add(long long k,long long b){ pos = j;
6.5 Suffix Array (Implementation 1) . . . . . . . . . 14 k = -k; b = -b; }
6.6 Suffix Array (Implementation 2) . . . . . . . . . 14 uxix cur; }
cur.k=k;
6.7 Suffix Tree . . . . . . . . . . . . . . . . . 14 cur.b=b; dp[k][m] = best;
. . . . . . . . . . . . . . . . .
1
6.8 Z Function 15 while(top>=2){
Yerevan State University
calcdp(k, l, m-1, optl, pos); if (T == NULL) return 0;
calcdp(k, m+1, r, pos, optr); for (int j = L; j <= R; ++j) { //extCreate(T, tl, tr); // eats more useless memory
} int val = dp[l][j] + dp[j+1][r] + getsum(l, r); if (tl == lx && tr == rx) return intGet(T->root, 0, N, ly, ry
if (val < dp[l][r]) { );
scanf("%d", &n); dp[l][r] = val; int tm = (tl + tr) / 2;
for (int i = 1; i <= n; ++i) { opt[l][r] = j; if (rx <= tm) return extGet(T->l, tl, tm, lx, rx, ly, ry);
scanf("%d", &a[i]); } if (lx > tm) return extGet(T->r, tm + 1, tr, lx, rx, ly, ry);
} } return gcd(extGet(T->l, tl, tm, lx, tm, ly, ry), extGet(T->r,
} } tm + 1, tr, tm + 1, rx, ly, ry));
// init } }
for (int k = 1; k <= n; ++k) { }
// init ? void extUpdate(extPnode &T, int tl, int tr, int x, int y, LL val)
calcdp(k, 1, n, 1, n); {
} extCreate(T, tl, tr);
if (tl == tr) {
2 Data Structures }
intUpdate(T->root, 0, N, y, val);
return;
FOR(k, N) FOR(i, N) { void intCreate(intPnode &T, int tl, int tr) { struct CentroidDecomposition {
dp[k][i] = INF; if (!T) T = new intNode(tl, tr); vector<int> G[N];
} } bool used[N];
dp[0][0] = 0; int size[N]; // subtree size
for (int i = 0; i <= n; ++i) { LL intValue(intPnode &T) { int maxi[N]; // max subtree size
opt[0][i] = 1; return T == NULL ? 0 : T->g;
} } struct node {
for (int k = 1; k <= n; ++k) { int v;
dp[k][0] = 0; LL intGet(intPnode &T, int tl, int tr, int l, int r) { vector<node*> to;
opt[k][0] = 1; if (T == NULL) return 0; unordered_map<int, int> id; // child id of a vertex in
opt[k][n+1] = n; //intCreate(T, tl, tr); // eats more useless memory subtree
for (int i = n; i >= 1; --i) { if (tl == l && tr == r) return intValue(T); vector<int> nodes; // nodes in subtree
for (int j = opt[k-1][i]; j <= opt[k][i+1]; ++j) { int tm = (tl + tr) / 2;
int val = dp[k-1][j-1] + cost(j, i); if (r <= tm) return intGet(T->l, tl, tm, l, r); // keep additional data here
if (val < dp[k][i]) { if (l > tm) return intGet(T->r, tm + 1, tr, l, r);
dp[k][i] = val; return gcd(intGet(T->l, tl, tm, l, tm), intGet(T->r, tm + 1, node(int v = 0) : v(v) {}
opt[k][i] = j; tr, tm + 1, r)); };
} } typedef node* pnode;
} pnode root;
} void intUpdate(intPnode &T, int tl, int tr, int pos, LL val, bool
} multipleLines = false, intPnode lson = NULL, intPnode rson void dfs(int u, int par, vector<int> &mas) {
} = NULL) { mas.pb(u);
intCreate(T, tl, tr); size[u] = 1;
if (tl == tr) { maxi[u] = 1;
if (!multipleLines) T->g = val; for (int to : G[u]) {
else { if (to != par && !used[to]) {
1.5 Knuth Optimization (Type 2) LL left = intGet(lson, 0, N, tl, tr);
LL right = intGet(rson, 0, N, tl, tr);
dfs(to, u, mas);
size[u] += size[to];
T->g = gcd(left, right); maxi[u] = max(maxi[u], size[to]);
} }
// dp[i][j] = Min_{i < k < j} { dp[i][k] + dp[k+1][j] + cost(i, j return; }
) } } }
// if opt[l][r-1] <= opt[l][r] <= opt[l+1][r] int tm = (tl + tr) / 2;
if (pos <= tm) intUpdate(T->l, tl, tm, pos, val, void buildData(pnode root) {
LL dp[N][N]; multipleLines, lson, rson); root->nodes.pb(root->v);
int opt[N][N]; else intUpdate(T->r, tm + 1, tr, pos, val, multipleLines, for (int i = 0; i < sz(root->to); ++i) {
lson, rson); pnode to = root->to[i];
T->g = gcd(intValue(T->l), intValue(T->r)); for (int u : to->nodes) {
int cost(int l, int r) { } root->nodes.pb(u);
// ... root->id[u] = i;
} struct extNode { }
extNode *l, *r; }
void solve() { int tl, tr; }
intNode *root;
for (int l = n-1; l >= 0; --l) { pnode build(int u) {
dp[l][l] = 0; extNode(int tl = 0, int tr = 0, intNode *root = NULL, extNode vector<int> mas;
opt[l][l] = l; *l = NULL, extNode *r = NULL) : dfs(u, -1, mas);
tl(tl), tr(tr), root(root), l(l), r(r) { } int n = sz(mas);
if (l+1 < n) { }; int best = N, pos = -1;
dp[l][l+1] = cost(l, l+1); typedef extNode* extPnode; for (int u : mas) {
opt[l][l+1] = l; extPnode root; maxi[u] = max(maxi[u], n - size[u]);
} if (maxi[u] < best) {
void extCreate(extPnode &T, int tl, int tr) { best = maxi[u];
for (int r = l+2; r < n; ++r) { if (!T) T = new extNode(tl, tr); pos = u;
dp[l][r] = INF; } }
}
int L = opt[l][r-1]; LL extGet(extPnode &T, int tl, int tr, int lx, int rx, int ly, u = pos;
2
int R = opt[l+1][r]; int ry) { used[u] = true;
Yerevan State University
node *root = new node(u); dfs(1);
for (int to : G[u]) chains.clear();
if (!used[to]) root->to.pb(build(to));
buildData(root);
2.4 Heavy-Light Decomposition makeHLD(1);
for (int i = 0; i < sz(chains); ++i) reverse(all(chains[i]));
return root; for (int i = 0; i < sz(chains); ++i)
} for (int j = 0; j < sz(chains[i]); ++j)
const int N = 100007; pos[chains[i][j]] = dep[chains[i][j]] - dep[chains[i][0]];
} cd; int n, dep[N], par[N], size[N];
vector<int> G[N]; S.clear();
bool heavy[N]; S.resize(sz(chains));
// build for (int i = 0; i < sz(chains); ++i) {
for (int i = 0; i < n - 1; ++i) { vector<vector<int> > chains; S[i].init(sz(chains[i]));
int u, v; int id[N], pos[N]; for (int j = 0; j < S[i].n; ++j)
scanf("%d%d", &u, &v); S[i].update(1, 0, S[i].n - 1, j, w[chains[i][j]]);
cd.G[u].pb(v); void dfs(int u, int p = 0, int d = 0) { }
cd.G[v].pb(u); par[u] = p;
} dep[u] = d;
cd.root = cd.build(1); size[u] = 1;
int maxi = 0, pos = 0;
for (int i = 0; i < sz(G[u]); ++i) {
int to = G[u][i];
2.5 Persistent Segment Tree With
if (to != p) {
Range Updates
2.3 DSU With Rollbacks dfs(to, u, d + 1);
if (size[to] > maxi) {
maxi = size[to];
pos = to; struct node
struct DSU_withRollbacks { } {
int *par, *size; size[u] += size[to]; node *l, *r;
int n, ncomps; } int sum, add;
}
enum { PAR, SIZE, NCOMPS }; heavy[pos] = true; node(int sum = 0, int add = 0) : sum(sum), add(add), l(NULL),
} r(NULL) { } // creates a leaf
struct Change {
int type, index, oldValue; int makeHLD(int u) { node(node *left, node *right) // creates a node
Change() {} bool f = false; {
Change(int type, int index, int oldValue) : type(type), for (int i = 0; i < sz(G[u]); ++i) { add = 0;
index(index), oldValue(oldValue) {} int to = G[u][i].first; sum = 0;
} *changes; if (to == par[u]) continue; l = left;
int top; int ind = makeHLD(to); r = right;
if (ind != -1) { }
void init(int n) { chains[ind].pb(u); };
this->n = n; id[u] = ind; typedef node* pnode;
par = new int [n]; f = true;
size = new int [n]; } inline int get(pnode T, int tl, int tr)
changes = new Change[2 * n]; } {
ncomps = n; if (!f) { if (!T)
top = 0; id[u] = sz(chains); {
FOR(i, n) { chains.pb(vector<int>()); return 0;
par[i] = i; chains[id[u]].pb(u); }
size[i] = 1; } return T->add * (tr - tl + 1) + T->sum;
} if (heavy[u]) return id[u]; }
} return -1;
} inline void fix(pnode &T, int tl, int tr)
int get(int i) { {
if (par[i] == i) return i; struct segTree { int tm = (tl + tr) / 2;
return get(par[i]); T->sum = get(T->l, tl, tm) + get(T->r, tm + 1, tr);
} int n, *T; }
void unite(int i, int j) { void init(int s) { pnode push(pnode &T, int tl, int tr)
i = get(i); n = s; {
j = get(j); T = new int[4 * s + 2]; pnode ret = new node();
if (i == j) return; memset(T, 0, 4 * (4 * s + 2)); if (T->l)
if (size[i] < size[j]) swap(i, j); } {
ret->l = new node(T->l->l, T->l->r);
changes[top++] = Change(PAR, j, par[j]); // ... ret->l->add = T->l->add;
changes[top++] = Change(SIZE, i, size[i]); }; ret->l->sum = T->l->sum;
changes[top++] = Change(NCOMPS, -1, ncomps); vector<segTree> S; ret->l->add += T->add;
}
size[i] += size[j]; int getLca(int u, int v) { if (T->r)
par[j] = i; while (id[u] != id[v]) { {
--ncomps; if (dep[chains[id[u]][0]] < dep[chains[id[v]][0]]) v = par[ ret->r = new node(T->r->l, T->r->r);
} chains[id[v]][0]]; ret->r->add = T->r->add;
else u = par[chains[id[u]][0]]; ret->r->sum = T->r->sum;
int snapshot() { } ret->r->add += T->add;
return top; return dep[u] < dep[v] ? u : v; }
} } ret->sum = T->sum + (tr - tl + 1) * T->add;
ret->add = 0;
void toSnapshot(int snap) { int go(int u, int v) { return ret;
while (top != snap) { int ret = -1000000000; }
--top; while (id[u] != id[v]) {
if (changes[top].type == PAR) { ret = max(ret, S[id[u]].get(1, 0, S[id[u]].n - 1, 0, pos[u pnode build(int a[], int tl, int tr)
par[changes[top].index] = changes[top].oldValue; ])); {
} u = par[chains[id[u]][0]]; if (tl == tr)
if (changes[top].type == SIZE) { } {
size[changes[top].index] = changes[top].oldValue; if (u == v) return ret; return new node(a[tl], 0);
} ret = max(ret, S[id[u]].get(1, 0, S[id[u]].n - 1, pos[v] + 1, }
if (changes[top].type == NCOMPS) { pos[u])); int tm = (tl + tr) / 2;
ncomps = changes[top].oldValue; return ret; pnode ret = new node(build(a, tl, tm), build(a, tm + 1, tr));
} } fix(ret, tl, tr);
} return ret;
} // build }
3
};
Yerevan State University
pnode rsq(pnode &T, int tl, int tr, int l, int r, int &s) T = (A ? A : B); split(cur->l, cnt, L, cur->l);
{ } R = cur;
pnode ret = push(T, tl, tr); else if (A->pr > B->pr) { }
if (tl == l && tr == r) merge(A->r, B, A->r); else {
{ T = A; split(cur->r, cnt - 1 - getSize(cur->l), cur->r, R);
s = ret->sum; } L = cur;
return ret; else { }
} merge(A, B->l, B->l); fix(L);
int tm = (tl + tr) / 2; T = B; fix(R);
if (r <= tm) } }
{ fix(T);
ret->l = rsq(ret->l, tl, tm, l, r, s); } void merge(pnode L, pnode R, pnode &T) {
} if (!L || !R) {
else if (l > tm) void split(pnode T, int x, pnode <, pnode &RT, int add = 0) { T = copyNode((L ? L : R));
{ if (!T) { return;
ret->r = rsq(ret->r, tm + 1, tr, l, r, s); LT = RT = 0; }
} return; int lsize = getSize(L);
else } int rsize = getSize(R);
{ int curx = add + getSize(T->l); if (rand() % (lsize + rsize) < lsize) {
int s1, s2; if (x <= curx) { T = copyNode(L);
ret->l = rsq(ret->l, tl, tm, l, tm, s1); split(T->l, x, LT, T->l, add); push(T);
ret->r = rsq(ret->r, tm + 1, tr, tm + 1, r, s2); RT = T; merge(T->r, R, T->r);
s = s1 + s2; } }
} else { else {
fix(T, tl, tm); split(T->r, x, T->r, RT, add + 1 + getSize(T->l)); T = copyNode(R);
return ret; LT = T; push(T);
} } merge(L, T->l, T->l);
fix(LT); }
pnode update(pnode &T, int tl, int tr, int l, int r, int delta) fix(RT); fix(T);
{ } }
if (tl == l && tr == r)
{ void print(pnode T) {
pnode ret = new node(T->l, T->r); if (!T) return;
ret->add = T->add + delta; push(T);
ret->sum = T->sum;
return ret; 2.7 Persistent Treap print(T->l);
putchar(T->data);
} print(T->r);
int tm = (tl + tr) / 2; }
pnode ret = push(T, tl, tr); struct node {
if (r <= tm) node *l, *r;
{ bool rev;
ret = new node(update(ret->l, tl, tm, l, r, delta), ret-> int size;
}
r); char data;
2.8 Splay Tree
else if (l > tm) node(char data = ’a’) : data(data) {
{ l = r = NULL;
ret = new node(ret->l, update(ret->r, tm + 1, tr, l, r, rev = false; struct _node{
delta)); size = 1; int in;
} } node l, r;
else }; node p;
{ typedef node* pnode; };
ret = new node(update(ret->l, tl, tm, l, tm, delta), bool is_root(node v){
update(ret->r, tm + 1, tr, tm + 1, r, delta)); const int N = 200007; return v->p==NULL || (v->p->l!=v && v->p->r!=v);
} char st[N]; }
fix(ret, tl, tr); bool Type(node v){
return ret; pnode copyNode(pnode other) { return v->p->r == v;
} if (other == NULL) return NULL; }
pnode ret = new node(); void connect(node v,node p,bool ty){
ret->l = other->l;
ret->r = other->r; (ty?p->r:p->l) = v;
ret->rev = other->rev; if(v)
2.6 Treap With Implicit Key ret->size = other->size;
ret->data = other->data; }
v->p = p;
4
if (!A || !B) { if (getSize(cur->l) >= cnt) { rotate( ( Type(n)ˆType(p) ) ? n:p );
Yerevan State University
rotate(n); x = a; if (x > eps) return 1;
} y = b; return 0;
} z = c; }
node expose(node n){ }
node last = NULL; bool inside(pt A, vector<plane>& faces, pt O) {
for(node m = n;m;m = m->p){ void print() { for (auto t : faces) {
splay(m); cerr << "( " << x << " " << y << " " << z << " ) "; int need_sign = sign(dist_from_plane(O, t));
m->r = last; } int cur_sign = sign(dist_from_plane(A, t));
last = m; if (need_sign * cur_sign == -1) return false;
update(m); pt operator + (const pt &o) const { }
} return pt(x+o.x, y+o.y, z+o.z); return true;
splay(n); } }
return last;
} LD dist2(const pt &o) const { void dfs(int u, vector<vector<int> >& G, vector<bool>& used,
return sqrt((x-o.x)*(x-o.x) + (y-o.y)*(y-o.y)); vector<int>& order) {
node Par(node v){ } order.pb(u);
v = v->l; used[u] = true;
while(v){ pt operator - (const pt &o) const { for (auto to : G[u]) {
push(v); return pt(x-o.x, y-o.y, z-o.z); if (!used[to]) {
if(v->r) } dfs(to, G, used, order);
v = v->r; }
else pt operator * (LD c) const { }
break; return pt(x*c, y*c, z*c); }
} }
splay(v); void solve() {
return v; pt operator / (LD c) const { int n;
} return pt(x/c, y/c, z/c); scanf("%d", &n);
}
p.resize(n);
LD len() const { FOR(i, n) {
return sqrtl(x*x + y*y + z*z); p[i].read();
2.9 2D Fenwick Tree Range Updates } }
3 Geometry }
{
// note A, B, C stay undefined
vector<vector<int> > G(n);
int some_vertex = -1;
for (auto pr : M) {
if (pr.second >= 2) continue;
plane(int i, int j, int k): A(p[i]), B(p[j]), C(p[k]), i(i), int i = pr.first / N;
3.1 3D Convex Hull j(j), k(k) { int j = pr.first % N;
pt norm = cross(B-A, C-A).normalize(); some_vertex = i;
a = norm.x; G[i].pb(j);
const int N = 1007; b = norm.y; G[j].pb(i);
const LD pi = acosl(-1.0); c = norm.z; }
const LD eps = 1e-9; d = -a * A.x - b * A.y - c * A.z; assert(some_vertex != -1);
const LD INF = 1e18; } vector<bool> used(ptr, false);
}; vector<int> order;
struct pt { dfs(some_vertex, G, used, order);
LD x, y, z;
LD dist_from_plane(pt A, plane& t) { vector<plane> to_add;
pt (LD x=0, LD y=0, LD z=0): x(x), y(y), z(z) { return (A.x * t.a + A.y * t.b + A.z * t.c + t.d) / sqrtl(t.a* FOR(i, sz(order)) {
} t.a + t.b*t.b + t.c*t.c); int j = (i+1)%sz(order);
} int u = order[i];
void read() { int v = order[j];
int a, b, c; LD sign(LD x) { to_add.pb(plane(ptr, u, v));
5
scanf("%d%d%d", &a, &b, &c); if (x < -eps) return -1; }
Yerevan State University
if (fabs(p[i].x - midx) < best) { }
for (auto t : to_add) { j = tsz - 1; it = hull.lower_bound(cur);
new_faces.pb(t); while (j >= 0 && p[i].y - p[t[j]].y < best) { // go right
} update(i, t[j]); while (!hull.empty() && it != hull.end()) {
faces = new_faces; j--; if (cmp(k, b, *it) == 1) deleteSegment(*it);
} } else break;
t[tsz++] = i; it = hull.lower_bound(cur);
} } }
} if (hull.empty()) {
addSegment(cur);
} return;
}
3.2 Closest Point Pair // run
scanf("%d", &n);
// intersect with left and right
it = hull.lower_bound(cur);
sort(p, p + n, cmp1); if (it == hull.begin()) {
struct point { solve(0, n - 1); if (cmp(k, b, *it) == -1) return;
double x, y; else {
int ind; LD x = (LD)(b - it->b) / (it->k - k);
double operator + (const point & a) const segment tmp = *it;
{ tmp.x1 = x;
}
return sqrt((a.x - x) * (a.x - x) + (a.y - y) * (a.y - y));
3.3 Dynamic Upper Convex Hull deleteSegment(*it);
addSegment(tmp);
} p[100007], temp[100007]; // temp for merge cur.x2 = x;
double best = 1e18; addSegment(cur);
int n, ind1, ind2; const int N = 100007; }
int n, x[N], c[N], t[N]; }
bool cmp1(const point & a, const point & b) // sort by x LL dp[N]; else if (it == hull.end()) {
{ --it;
return (a.x < b.x || (a.x == b.x && a.y < b.y)); const LD eps = 1e-12; if (cmp(k, b, *it) == -1) return;
} struct segment { LD x = (LD)(b - it->b) / (it->k - k);
LL k, b; // y = kx + b segment tmp = *it;
bool cmp2(const point & a, const point & b) // sort by y LD x1, x2; // x1 < x2 tmp.x2 = x;
{ deleteSegment(*it);
return (a.y < b.y || (a.y == b.y && a.x < b.x)); segment(LL k = 0, LL b = 0, LD x1 = -1e7, LD x2 = +1e7) : k(k) addSegment(tmp);
} , b(b), x1(x1), x2(x2) {} cur.x1 = x;
addSegment(cur);
void merge(int l, int r) // merge for merge_sort by y bool operator < (const segment &o) const { }
{ if (k != o.k) return k < o.k; else {
int m = (l + r) / 2, i = l, j = m + 1, k; return b < o.b; auto lit = it; --lit;
for (k = l; k <= r; ++k) { } auto rit = it;
if (i > m) { }; if (cmp(k, b, *lit) == -1 || cmp(k, b, *rit) == -1) return;
temp[k] = p[j++]; LD x1 = (LD)(b - lit->b) / (lit->k - k);
} struct segment2 { LD x2 = (LD)(b - rit->b) / (rit->k - k);
else if (j > r) { LL k, b; segment t1 = *lit;
temp[k] = p[i++]; LD x; segment t2 = *rit;
} deleteSegment(t1);
else if (cmp2(p[i], p[j])) { segment2(LL k = 0, LL b = 0, LD x = 0.0) : k(k), b(b), x(x) {} deleteSegment(t2);
temp[k] = p[i++]; t1.x2 = x1;
} bool operator < (const segment2 &o) const { t2.x1 = x2;
else { if (fabsl(x - o.x) < eps) return k < o.k; cur.x1 = x1;
temp[k] = p[j++]; return x < o.x; cur.x2 = x2;
} } addSegment(t1);
} }; addSegment(cur);
for (k = l; k <= r; ++k) { set<segment2> hull2; addSegment(t2);
p[k] = temp[k]; set<segment> hull; }
} }
} int cmp(LL k, LL b, const segment &s) {
LD y1line = k * s.x1 + b; LL getMax(LL x) {
void update(int i, int j) { LD y2line = k * s.x2 + b; segment2 t(-(1LL << 58), 0, x);
double dis = p[i] + p[j]; LD y1seg = s.k * s.x1 + s.b; auto it = hull2.lower_bound(t);
if (dis < best) { LD y2seg = s.k * s.x2 + s.b; --it;
best = dis; if (y1line < y1seg + eps && y2line < y2seg + eps) return -1; return x * it->k + it->b;
ind1 = p[i].ind; if (y1line + eps > y1seg && y2line + eps > y2seg) return +1; }
ind2 = p[j].ind; return 0;
if (ind1 > ind2) { }
swap(ind1, ind2);
} inline void addSegment(segment s) {
}
} hull.insert(s);
hull2.insert(segment2(s.k, s.b, s.x1));
3.4 Farthest Point Pair
}
void solve(int l, int r) { struct pt {
double midx; inline void deleteSegment(segment s) {
int i, j, m; hull.erase(s); LD x, y;
if (r - l <= 3) hull2.erase(segment2(s.k, s.b, s.x1));
{ } pt(LD x=0, LD y=0): x(x), y(y) {
for (i = l; i <= r; ++i) {
for (j = i + 1; j <= r; ++j) { void addLine(LL k, LL b) { }
update(i, j); //lines.pb(mp(k, b));
} void read() {
} segment cur(k, b); int a, b;
sort(p + l, p + r + 1, cmp2); if (hull.empty()) { scanf("%d%d", &a, &b);
return; addSegment(cur); x = a;
} return; y = b;
m = (l + r) / 2; } }
midx = p[m].x; if (hull.count(cur)) return;
solve(l, m); auto it = hull.lower_bound(cur); pt operator + (const pt &o) const {
solve(m + 1, r); // go left return pt(x+o.x, y+o.y);
merge(l, r); while (!hull.empty() && it != hull.begin()) { }
--it;
static int t[100007]; if (cmp(k, b, *it) == 1) deleteSegment(*it); pt operator - (const pt &o) const {
int tsz = 0; else break; return pt(x-o.x, y-o.y);
6
for (i = l; i <= r; ++i) { it = hull.lower_bound(cur); }
Yerevan State University
pt amax = A[0];
LD dist(const pt &o) const { pt operator + (const pt &o) const { for (auto P : A) {
return (x-o.x)*(x-o.x) + (y-o.y)*(y-o.y); return pt(x+o.x, y+o.y); if (dot(P, dir) > dot(amax, dir)) amax = P;
} } }
7
} planes) if (t < -1.0 + eps) return pi;
Yerevan State University
if (t > 1.0 - eps) return 0; for (pt P : mas[i]) A[na++] = P; pt& D = seg[o.id].second;
return acosl(t); } /*
} nb = 0; ete unenq vertical hatvacner, hetevyal kerpov enq y hashvum
for (int i = m + 1; i <= r; ++i) { , aglorithmy jisht e ashxatum naev
void minkowski_sum(int na, pt *A, int nb, pt *B, int &nc, pt *C) for (pt P : mas[i]) B[nb++] = pt(-P.x, -P.y); vertical uxixneri depqum, vorpes y yntrum enq kamayakan,
{ } orinak hatvaci araji keti Y
int posa = 0; convex_hull(na, A); bolor verticalnery skzbic insert en arvum, heto deleta
FOR(i, na) { convex_hull(nb, B); TESTED
if (A[i].x > A[posa].x || (A[i].x == A[posa].x && A[i].y ete ayspes anenq, nerqevum(144-159) petq che pttel ketery
> A[posa].y)) posa = i; if (na == 0 || nb == 0) return; LD y1 = fabsl(B.x - A.x) > eps ? A.y + (B.y - A.y) * (
} sweepX - A.x) / (B.x - A.x) : A.y;
int posb = 0; minkowski_sum(na, A, nb, B, nc, C); LD y2 = fabsl(D.x - C.x) > eps ? C.y + (D.y - C.y) * (
FOR(i, nb) { FOR(i, nc) { sweepX - C.x) / (D.x - C.x) : C.y;
if (B[i].x > B[posb].x || (B[i].x == B[posb].x && B[i].y ans = max(ans, C[i].x * C[i].x + C[i].y * C[i].y); */
> B[posb].y)) posb = i; } LD y1 = A.y + (B.y - A.y) * (sweepX - A.x) / (B.x - A.x);
} } LD y2 = C.y + (D.y - C.y) * (sweepX - C.x) / (D.x - C.x);
nc = 0; if (fabsl(y1 - y2) < eps) return id < o.id;
C[nc++] = A[posa] + B[posb]; return y1 < y2;
LD rot = 0.0; }
while (true) { };
int nposa = (posa + 1) % na;
int nposb = (posb + 1) % nb; 3.7 Pair of Intersecting Segments set<segment> status;
8
for (int i = l; i <= m; ++i) { pt& C = seg[o.id].first;
Yerevan State University
#define task "areas"
for (int i = 1; i < sz(p); ++i) { freopen(task".in", "r", stdin);
3.8 Minimum Enclosing Circle (Ran- if (inside_circle(p[i], C, R)) continue;
vector<pt> mas(p.begin(), p.begin()+i);
freopen(task".out", "w", stdout);
#endif
domized Incremental Algorithm) }
two_points_known(mas, A, p[i], C, R);
int nlines;
} cin >> nlines;
lines.resize(nlines);
// One can do 2 nested ternary searches: O(N * (logN)ˆ2) LD get(vector<pt> &p) { for (int i = 0; i < nlines; ++i)
struct MEC { random_shuffle(all(p)); cin >> lines[i].first.x >> lines[i].first.y >> lines[i].
pt C = p[0]; second.x >> lines[i].second.y;
bool inside_circle(pt A, pt C, LD R) { LD R = 0.0; in.resize(nlines);
return A.dist2(C) < R + eps;
} for (int i = 1; i < sz(p); ++i) { for (int i = 0; i < nlines; ++i) {
if (inside_circle(p[i], C, R)) continue; for (int j = i + 1; j < nlines; ++j) {
LD cross(pt u, pt v) { vector<pt> mas(p.begin(), p.begin()+i); pt A = lines[i].first;
return u.x * v.y - u.y * v.x; one_point_known(mas, p[i], C, R); pt B = lines[i].second;
} } pt C = lines[j].first;
pt D = lines[j].second;
pt intersect_bisectors(pt A, pt B, pt C, pt D) { return R;
pt AB = (A+B) / 2.0; } LD a1 = B.y - A.y;
pt CD = (C+D) / 2.0; LD b1 = A.x - B.x;
} mec; LD c1 = B.x * A.y - B.y * A.x;
pt n1 = A - B;
pt n2 = C - D; LD a2 = D.y - C.y;
LD b2 = C.x - D.x;
LD a1 = n1.x; LD c2 = D.x * C.y - D.y * C.x;
LD b1 = n1.y;
LD c1 = -a1 * AB.x - b1 * AB.y; 4 Graphs LD det = a1 * b2 - a2 * b1;
if (fabsl(det) < eps) continue;
LD a2 = n2.x;
LD detx = -c1 * b2 + c2 * b1;
LD b2 = n2.y;
LD c2 = -a2 * CD.x - b2 * CD.y; 4.1 Facet Finding LD dety = -a1 * c2 + a2 * c1;
mas.pb(pt(detx / det, dety / det));
LD det = a1 * b2 - a2 * b1; in[i].pb(mas.back());
assert(fabsl(det) > eps); const LD eps = 1e-12; in[j].pb(mas.back());
struct pt { }
LD detx = c2 * b1 - c1 * b2; LD x, y; }
LD dety = c1 * a2 - c2 * a1; pt(LD x = 0.0, LD y = 0.0) : x(x), y(y) {}; unique(mas);
}; for (int i = 0; i < nlines; ++i) unique(in[i]);
return pt(detx/det, dety/det); typedef pt vect; int n = sz(mas);
} vector<pair<pt, pt> > lines; G.resize(n);
vector<vector<pt> > in; for (int i = 0; i < nlines; ++i) {
void update_ans(pt O, vector<pt>& p, pt A, pt B, pt& C, LD& R vector<vector<int> > G; int cnt = sz(in[i]);
) { vector<pt> mas; for (int j = 1; j < cnt; ++j) {
LD cur = O.dist2(A); int n, nlines; int u = find(in[i][j]);
if (cur > R) return; map<LL, LD> M; int v = find(in[i][j - 1]);
for (auto E : p) { G[u].pb(v);
if (!inside_circle(E, O, cur)) return; bool cmp(const pt &A, const pt &B) { G[v].pb(u);
} if (fabsl(A.x - B.x) < eps) return A.y + eps < B.y; }
R = cur; return A.x + eps < B.x; }
C = O; } for (int i = 0; i < n; ++i) {
} for (int j : G[i]) {
void unique(vector<pt> &mas) { vect u(mas[j].x - mas[i].x, mas[j].y - mas[i].y);
void consider(vector<pt> &p, vector<pt>& side, pt A, pt B, pt if (sz(mas) == 0) return; vector<int> facet;
& C, LD& R) { sort(all(mas), cmp); facet.pb(i);
pt mini(INF,INF,INF); vector<pt> tmp; dfs(j, u, facet);
pt maxi(-INF, -INF, -INF); tmp.pb(mas[0]); if (sz(facet) == 0) continue;
for (int i = 1; i < sz(mas); ++i) //cerr << "Facet finded !!!\n";
for (auto E : side) { if (cmp(mas[i], mas[i - 1]) || cmp(mas[i - 1], mas[i])) tmp //for (int p : facet) cerr << "\t" << mas[p].x << " " <<
pt X = intersect_bisectors(A, E, A, B); .pb(mas[i]); mas[p].y << endl;
if (X < mini) mini = X; mas = tmp; //cerr << endl;
if (maxi < X) maxi = X; } LD S = 0.0;
} for (int u = 1; u < sz(facet); ++u) {
int find(pt &A) { pt B = mas[facet[u]];
if (mini.x < INF/2) { for (int i = 0; i < sz(mas); ++i) pt A = mas[facet[u - 1]];
update_ans(mini, p, A, B, C, R); if (!cmp(mas[i], A) && !cmp(A, mas[i])) return i; S += (A.y + B.y) * (B.x - A.x);
update_ans(maxi, p, A, B, C, R); throw "no such point finded"; }
} } pt A = mas[facet.back()];
} pt B = mas[facet.front()];
bool ccw(vect &u, vect &v) { S += (A.y + B.y) * (B.x - A.x);
void two_points_known(vector<pt>& p, pt A, pt B, pt& C, LD& R return u.x * v.y - u.y * v.x > eps; S = fabsl(S) / 2.0;
) { } sort(all(facet));
pt dir = B-A; LL h = 0;
void dfs(int i, vect &u, vector<int> &facet) { for (int p : facet) h = 1000000007 * h + p;
R=INF; if (i == facet.front()) return; if (S > 1e-9) M[h] = S;
update_ans((A+B)/2.0, p, A, B, C, R); facet.pb(i); }
vect best = u; }
vector<pt> lside, rside; int pos = -1; vector<LD> S;
for (auto E : p) { for (int j : G[i]) { for (pair<LL, LD> p : M) S.pb(p.second);
if (cross(dir, E-A) > +eps) lside.pb(E); vect v(mas[j].x - mas[i].x, mas[j].y - mas[i].y); cout << sz(S) << endl;
if (cross(dir, E-A) < -eps) rside.pb(E); if (ccw(best, v) && ccw(u, v)) best = v, pos = j; sort(all(S));
} } for (LD s : S) cout << fixed << setprecision(9) << s << endl;
consider(p, lside, A, B, C, R); if (pos == -1) facet.clear();
consider(p, rside, A, B, C, R); else dfs(pos, best, facet); #ifdef harhro94
} } cerr << fixed << setprecision(3) << "\nExecution time = " <<
clock() / 1000.0 << "s\n";
void one_point_known(vector<pt>& p, pt A, pt& C, LD& R) { int main() { #endif
random_shuffle(all(p)); #ifdef harhro94 return 0;
freopen("input.txt", "r", stdin); }
C = (p[0] + A) / 2.0; //freopen("output.txt", "w", stdout);
9
R = p[0].dist2(A) / 2.0; #else
Yerevan State University
for (int id : G[u]) { }
int to = E[id].to;
4.2 LCA O(1) if (E[id].cap - E[id].flow > 0 && dist[to] > dist
[u] + E[id].cost) {
void unite(int u, int v, int newCand) {
u = getPar(u);
dist[to] = dist[u] + E[id].cost; v = getPar(v);
if (!is[to]) { if (rand() & 1) {
const int N = 100007; is[to] = true; swap(u, v);
int n, timer, tin[N], id[N], ptr, mas[N + N], pos[N], mlog[N + N Q[r++] = to; }
], mini[20][N + N]; if (r == N) r = 0; par[u] = v;
vector<int> G[N]; } cand[v] = newCand;
} }
void dfs(int u, int p = -1) { }
id[timer] = u; } void dfs(int u) {
tin[u] = timer++; } used[u] = true;
pos[u] = ptr; par[u] = u;
mas[ptr++] = tin[u]; bool dijkstra() { cand[u] = u;
for (int to : G[u]) { FOR(i, n) dist[i] = INF; for (int to : G[u]) {
if (to != p) { dist[s] = 0; if (!used[to]) {
dfs(to, u); set<pair<LL, int> > S; dfs(to);
mas[ptr++] = tin[u]; S.insert(mp(0, s)); unite(to, u, u);
} while (!S.empty()) { }
} int u = S.begin()->second; }
} S.erase(S.begin()); for (int i = 0; i < sz(query[u]); ++i) {
for (int id : G[u]) { int v = query[u][i].first;
int lca(int u, int v) { int to = E[id].to; if (used[v]) {
int l = pos[u], r = pos[v]; LL cost = E[id].cost + pi[u] - pi[to]; query[u][i].second = cand[getPar(v)];
if (l > r) swap(l, r); if (E[id].cap - E[id].flow > 0 && dist[to] > dist }
int k = mlog[r - l + 1]; [u] + cost) { }
int w = id[min(mini[k][l], mini[k][r - (1 << k) + 1])]; S.erase(mp(dist[to], to)); }
return w; pre[to] = u;
} preId[to] = id; void process() {
dist[to] = dist[u] + cost; for (int i = 0; i < m; ++i) {
S.insert(mp(dist[to], to)); int u = u1[i];
dfs(0); } int v = u2[i];
mlog[1] = 0; } pos1[i] = sz(query[u]);
for (int i = 2; i < ptr; ++i) mlog[i] = 1 + mlog[i >> 1]; } query[u].pb(mp(v, -1));
for (int i = 0; i < ptr; ++i) mini[0][i] = mas[i]; // new_pi = pi + dist, easy to prove pos2[i] = sz(query[v]);
for (int k = 0; k < 19; ++k) { FOR(i, n) { query[v].pb(mp(u, -1));
for (int i = 0; i < ptr; ++i) { if (dist[i] != INF) pi[i] += dist[i]; }
if (i + (1 << (k + 1)) - 1 >= ptr) break; } dfs(1);
mini[k + 1][i] = min(mini[k][i], mini[k][i + (1 << k)]); return dist[t] != INF; for (int i = 0; i < m; ++i) {
} } int p1 = pos1[i];
} int p2 = pos2[i];
void augment() { int u = u1[i];
int u = t; int v = u2[i];
LL minCap = INF; if (query[u][p1].second != -1)
LL totalCost = 0; lca[i] = query[u][p1].second;
4.3 Min Cost Max Flow (Dijkstra with while (u != s) {
int id = preId[u];
else if (query[v][p2].second != -1)
lca[i] = query[v][p2].second;
Potentials) minCap = min(minCap, E[id].cap - E[id].flow);
totalCost += E[id].cost;
else
assert(false);
u = pre[u]; }
} }
struct MCMF {
vector<Edge> E; ansFlow += minCap;
vector<int> G[N]; ansCost += minCap * totalCost;
int n, s, t;
int Q[N], pre[N], preId[N];
LL pi[N], dist[N];
u = t;
while (u != s) {
4.5 Online LCA
bool is[N]; int id = preId[u];
LL ansFlow, ansCost; E[id].flow += minCap; int n, m, par[N], dep[N], up[20][N];
E[id ˆ 1].flow -= minCap; vector<int> G[N];
void addEdge(int u, int v, LL cap, LL cost) { u = pre[u];
G[u].pb(sz(E)); } void dfs(int u, int p = 1, int d = 0) {
E.pb(Edge(v, cap, cost)); } par[u] = p;
G[v].pb(sz(E)); dep[u] = d;
E.pb(Edge(u, 0, -cost)); pair<LL, LL> mcmf() { for (int i = 0; i < sz(G[u]); ++i) {
} fordBellman(); int to = G[u][i];
FOR(i, n) pi[i] = dist[i]; if (to != p) dfs(to, u, d + 1);
void init(int n, int s, int t) { while (dijkstra()) { }
this->n = n; augment(); }
this->s = s; }
this->t = t; return mp(ansFlow, ansCost); int lca(int u, int v) {
assert(t < n); } if (dep[u] < dep[v]) swap(u, v);
FOR(i, n) G[i].clear(); int diff = dep[u] - dep[v];
E.clear(); } mf; for (int i = 0; (1 << i) <= diff; ++i)
ansFlow = ansCost = 0; if (((diff >> i) & 1) == 1) u = up[i][u];
} if (u == v) return u;
for (int i = 19; i >= 0; --i)
void fordBellman() { if (up[i][u] != up[i][v])
FOR(i, n) {
is[i] = false;
4.4 Offline LCA (Tarjan) u = up[i][u], v = up[i][v];
return up[0][u];
dist[i] = INF; }
}
int l = 0, r = 0; int n, m, timer, par[N], cand[N], u1[M], u2[M], pos1[M], pos2[M], // preprocessing
Q[r++] = s; lca[M];
dist[s] = 0; vector<pair<int, int> > query[M]; dfs(1);
is[s] = true; vector<int> G[N]; for (int i = 1; i <= n; ++i) up[0][i] = par[i];
while (l != r) { bool used[N]; for (int k = 1; k < 20; ++k)
int u = Q[l++]; for (int i = 1; i <= n; ++i)
10
if (l == N) l = 0; int getPar(int u) { up[k][i] = up[k - 1][up[k - 1][i]];
is[u] = false; return (par[u] == u ? u : (par[u] = getPar(par[u])));
Yerevan State University
return true;
}
4.6 Rooted Tree Isomorphism }
return false;
4.8 Hungarian Algorithm
}
// Slow string implementation vector<int> u (n+1), v (m+1), p (m+1), way (m+1);
// init some matching for (int i=1; i<=n; ++i) {
string dfsSlow(int root, int par, vector<int> *G) { for (int i = 1; i <= n + m; ++i) p[0] = i;
vector<string> childs; mt[i] = -1; int j0 = 0;
for (int to : G[root]) { vector<int> minv (m+1, INF);
if (to != par) childs.pb(dfsSlow(to, root, G)); for (int i = 1; i <= n; ++i) deg[i] = ptr[i]; vector<char> used (m+1, false);
} do {
sort(all(childs)); int size = 0; used[j0] = true;
string cur = "("; FOR(iter, n) int i0 = p[j0], delta = INF, j1;
for (auto s : childs) cur += s; { for (int j=1; j<=m; ++j)
cur += ")"; int u = -1; if (!used[j]) {
return cur; int best = N * N; int cur = a[i0][j]-u[i0]-v[j];
} for (int i = 1; i <= n; ++i) if (cur < minv[j])
{ minv[j] = cur, way[j] =
// fast algorithm, DETERMINISTIC if (deg[i] >= 1 && deg[i] < best) j0;
{ if (minv[j] < delta)
map<vector<int>, int> ID; best = deg[i]; delta = minv[j], j1 = j;
int curid = 0; u = i; }
} for (int j=0; j<=m; ++j)
int getId(vector<int> &v) { } if (used[j])
if (ID.count(v)) return ID[v]; if (u == -1) break; u[p[j]] += delta, v[j] -= delta;
ID[v] = curid++; deg[u] = 0; else
return curid - 1; FOR(i, ptr[u]) minv[j] -= delta;
} { j0 = j1;
int to = G[u][i]; } while (p[j0] != 0);
int dfs(int root, int par, set<int> *G) { if (mt[to] == -1) do {
vector<int> childs; { int j1 = way[j0];
for (int to : G[root]) { mt[to] = u; p[j0] = p[j1];
if (to != par) childs.pb(dfs(to, root, G)); mt[u] = to; j0 = j1;
} ++size; } while (j0);
sort(all(childs)); FOR(j, ptr[to]) --deg[G[to][j]]; }
return getId(childs); break;
} }
}
// faster algorithm: vector<int>’s in map is slow }
// we will hash that vectors then add hashes to the map
// kuhn
4.9 Cactus
map<LL, int> ID; for (int i = 1; i <= n; ++i)
int curid = 0; { int topc, tmr, tin[ N ], fup[ N ], p[ N ];
if (mt[i] == -1) vi gr[ N ], cycles[ N ], graph[ N ];
LL getVectorHash(vector<int> &v) { { vpi c[ N ];
static const LL P = 1000003; for (int j = 1; j <= n; ++j) used[j] = false; void add_cycle(int v,int to){
LL h = 1; size += kuhn(i); int cr = v;
for (int u : v) h = h * P + u; } ++ topc;
return h; } while(1){
}
c[ cr ].push_back( mp(topc,sz(cycles[topc])) );
// bfs from 2 unmatched sides cycles[ topc ].push_back( cr );
int getId(vector<int> &v) { for (int i = 1; i <= n + m; ++i) ans[i] = ’E’; if(cr==to)
LL h = getVectorHash(v); for (int i = 1; i <= n + m; ++i) break;
if (ID.count(h)) return ID[h]; { cr = p[cr];
ID[h] = curid++; if (mt[i] == -1) }
return curid - 1; { }
} ans[i] = ’N’; void dfs(int v,int par){
Q.push(i);
int dfs(int root, int par, set<int> *G) { } p[v] = par;
vector<int> childs; } tin[v] = fup[v] = ++ tmr;
for (int to : G[root]) { while (!Q.empty()) for(auto to:graph[v]){
if (to != par) childs.pb(dfs(to, root, G)); { if(to==par)
} int u = Q.front(); continue;
sort(all(childs)); Q.pop(); if(!tin[to]){
return getId(childs); if (ans[u] == ’N’) dfs(to,v);
} { fup[v] = min(fup[v],fup[to]);
FOR(i, ptr[u])
{ if(fup[to] > tin[v])
int to = G[u][i]; add_cycle(to,v);
4.7 Vertex Cover (Types of Vertices) if (ans[to] == ’E’)
{
}else
if(tin[to] < tin[v]){
ans[to] = ’A’; fup[v] = min(fup[v],tin[to]);
Q.push(to); add_cycle(v,to);
const int N = 2007; } }
int n, m, k, mt[N]; } }
int ptr[N], deg[N], G[N][N]; } }
bool used[N]; else
char ans[N]; { void update(vi & a,vi & b,int d){
queue<int> Q; int to = mt[u]; if(sz(b)+d > sz(a))a.resize(sz(b)+d,0);
if (ans[to] == ’E’) forn(i,sz(b))
bool kuhn(int u) { a[i+d] = add(a[i+d],b[i]);
{ ans[to] = ’N’; }
used[u] = true; Q.push(to); map< pii, vi > memo;
for (int i = 0; i < ptr[u]; ++i) } vi & solvefor(int x,int dad){
{ } if(memo.count(mp(x,dad)))return memo[ mp(x,dad) ];
int to = G[u][i]; } memo[ mp(x,dad) ] = {0,1};
if (mt[to] == -1 || (!used[mt[to]] && kuhn(mt[to]))) auto & ans = memo[ mp(x,dad) ];
{ for(auto p:c[x]){
11
mt[to] = u; int i = p.first;
mt[u] = to; int pos = p.second;
Yerevan State University
int c_len = sz(cycles[i]); if (A[i].first == B[j].first) return A[i].second * s + B[ for (int i = 2; i < 200; ++i)
if(i==dad)continue; j].second; if (is[i]) for (int j = i * i; j < N; j += i)
forn(j,c_len){ if (A[i].first < B[j].first) ++i; is[j] = false;
int d = (j-pos+c_len)%c_len; else ++j; for (int i = 0; i < N; ++i)
int y = cycles[i][j]; } if (is[i]) for (int j = i; j < N; j += i) d[j].pb(i);
if(d==0)continue; assert(false); }
update(ans,solvefor(y,i),d); }
if(c_len > 2) int power(int a, int n, int MOD) {
update(ans,solvefor(y,i),c_len-d) // to find square root int res = 1;
; while (n) {
} int g = findGenerator(p); if (n & 1) res = res * a % MOD;
} int r = discreteLog(g, a, p); a = a * a % MOD;
return ans; if (r & 1) puts("No root"); n >>= 1;
} else { }
int x1 = power(g, r / 2, p); return res;
int x2 = p - x1; }
if (x1 > x2) swap(x1, x2);
if (x1 == x2) { int findGenerator(int p) {
5 Math }
assert(p == 2);
puts("1");
if (gen[p]) return gen[p];
++cur;
while (true) {
else printf("%d %d\n", x1, x2); int g = rand() % (p - 1) + 1;
} if (used[g] == cur) continue;
5.1 Chinese Remainder Theorem used[g] = cur;
bool ok = true;
for (int i = 0; i < sz(d[p - 1]); ++i) {
int power(int a, int b, int mod) { int t = d[p - 1][i];
if (b == 0) return 1;
if (b & 1) return (a * power(a, b - 1, mod)) % mod;
5.3 Extended Euclid Algorithm if (power(g, (p - 1) / t, p) == 1) {
ok = false;
int ret = power(a, b >> 1, mod); break;
return (ret * ret) % mod; }
} int gcd(int a, int b, int &x, int &y) { }
if (a == 0) { if (ok) return (gen[p] = g);
int getInverse(int a, int mod) { x = 0; }
a %= mod; y = 1; }
return power(a, mod - 2, mod); return b;
} }
int x1, y1;
LL solve(vector<int> p, vector<int> r) { int g = gcd(b % a, a, x1, y1);
LL M = 1;
int n = sz(p);
x = y1 - (b / a) * x1;
y = x1; 5.6 Linear Time Precalculation of In-
return g;
for (int i = 0; i < n; ++i) M *= p[i];
vector<vector<int> > inv(n, vector<int>(n)); } verses
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (i != j) inv[i][j] = getInverse(p[i], p[j]); /*** O(MOD) methods to precalculate all inverses
vector<LL> x(n); a)
for (int i = 0; i < n; ++i) { 5.4 Fast Fourier Transform r[1] = 1;
for (int i=2; i<m; ++i)
x[i] = r[i];
for (int j = 0; j < i; ++j) { r[i] = (m - (m/i) * r[m%i] % m) % m;
x[i] = (x[i] - x[j]) * inv[j][i]; void DFT(comp *a, int n) {
x[i] %= p[i]; int bitlen = 0; b)
if (x[i] < 0) x[i] += p[i]; while ((1 << bitlen) < n) ++bitlen; r[a*b] = r[a] * r[b] // O(1)
} for (int i = 0; i < n; ++i) { r[p] = power(p, MOD-2) // O(log(MOD))
} int r = rev(i, bitlen); total: O(MOD)
LL ret = 0; if (i < r) swap(a[i], a[r]); ***/
LL cur = 1; }
for (int i = 0; i < n; ++i) { for (int len = 2; len <= n; len <<= 1) { const LL MOD = 1000000000 + 7LL;
ret += x[i] * cur; int half = (len >> 1); const int N = 2000007;
cur *= p[i]; comp wlen(cos(2 * pi / len), sin(2 * pi / len));
ret %= M; for (int i = 0; i < n; i += len) { LL f[N], invf[N];
cur %= M; comp power = 1; int lp[N];
} for (int j = i, l = i, r = i + half; j < i + half; ++j, int pr_cnt, pr[N];
return ret; ++l, ++r, power *= wlen) {
} comp u = a[l], v = power * a[r]; void sieve() {
a[j] = u + v; lp[1] = 1;
a[j + half] = u - v; for (int i = 2; i < N; ++i) {
} if (lp[i] == 0) {
} pr[pr_cnt++] = i;
5.2 Discrete Logarithm and Square }
}
}
lp[i] = i;
for (int j = 0; j < pr_cnt && pr[j] <= lp[i] && pr[j] * i
Root void inverseDFT(comp *a, int n) { < N; ++j) {
DFT(a, n); lp[pr[j] * i] = pr[j];
for (int i = 0; i < n; ++i) a[i] /= n; }
// g ˆ x = a (mod p) reverse(a + 1, a + n); }
int discreteLog(int g, int a, int p) { } }
int s = (int)sqrt(p + 0.0);
vector<pair<int, int> > A, B; LL power(LL a, LL b) {
int gs = power(g, s, p), cur = 1; if (b == 0) return 1;
for (int t = 0; t * s < p - 1; ++t, cur = cur * gs % p) { if (b & 1) return a * power(a, b-1) % MOD;
}
A.pb(mp(cur, t));
5.5 Generator of Zp LL r = power(a, b >> 1);
return r * r % MOD;
int invg = power(g, p - 2, p); }
cur = a;
for (int i = 0; i < s; ++i, cur = cur * invg % p) { ector<int> d[N]; inline LL inv(LL a) {
B.pb(mp(cur, i)); int cur, used[N]; return power(a, MOD-2);
} bool is[N]; }
sort(all(A)); int gen[N];
sort(all(B)); inline LL C(int n, int k) {
12
int i = 0, j = 0; void sieve() { if (k < 0 || k > n) return 0;
while (i < sz(A) && j < sz(B)) { fill(is + 2, is + N, true); return f[n] * invf[k] % MOD * invf[n-k] % MOD;
Yerevan State University
} } int i = p.second;
min_len[i] = N;
void precalc() { if (term[i]) min_len[i] = dep[i];
f[0] = 1; if (next_term[i] != -1) {
for (int i = 1; i < N; ++i) { min_len[i] = min(min_len[i], min_len[next_term[i
}
f[i] = i * f[i-1] % MOD;
sieve();
6 Strings }
}
]]);
}
} if (ch >=
assert(ch
’A’ && ch <= ’Z’) return ch - ’A’ + 26;
>= ’0’ && ch <= ’9’);
6.2 Discrete Manacer
return ch - ’0’ + 52;
}
n = strlen(st);
int l = 0, r = -1;
const int A = 64;
for (int i = 0; i < n; ++i) {
5.7 Simplex Algorithm const int N = 100007;
d1[i] = 1;
if (i <= r) d1[i] = min(d1[l + (r - i)], r - i + 1);
struct AC {
while (i + d1[i] < n && i - d1[i] >= 0 && st[i + d1[i]] ==
st[i - d1[i]]) ++d1[i];
namespace simplex{ int to[64][N], go[64][N];
if (i + d1[i] - 1 > r) {
const LD eps=1e-10; int par[N], dep[N], suff[N];
l = i - d1[i] + 1;
const int N=3000+10,M=3000+10; int cur_node;
r = i + d1[i] - 1;
int n,m; char pch[N];
}
int Left[M],Down[N],idx[N],va[N];
}
LD a[M][N],b[M],c[N],v; // additional information
l = 0, r = -1;
//maximize cTx, subject to Ax <= b and x >= 0 int next_term[N], min_len[N];
for (int i = 0; i < n; ++i) {
void init(int p,int q) { bool term[N];
d2[i] = 0;
n=p; m=q;
if (i <= r) d2[i] = min(d2[l + (r - i) + 1], r - i + 1);
for1(i,m) for1(j,n) a[i][j]=0; AC() {
while (i + d2[i] < n && i - d2[i] - 1 >= 0 && st[i + d2[i]]
for1(j,m) b[j]=0; for1(i,n) c[i]=0; memset(suff, -1, sizeof suff);
== st[i - d2[i] - 1]) ++d2[i];
for1(i,n) idx[i]=0; memset(go, -1, sizeof go);
if (i + d2[i] - 1 > r) {
v=0; memset(to, -1, sizeof to);
l = i - d2[i] + 1 - 1;
} cur_node = 1;
r = i + d2[i] - 1;
void pivot(int x,int y) { }
}
swap(Left[x],Down[y]);
}
LD k=a[x][y]; void add(string st) {
a[x][y]=1; b[x]/=k; int cur = 0;
int t=0; for (char symbol : st) {
for1(j,n) { int ch = code(symbol);
a[x][j]/=k; if (to[ch][cur] == -1) {
if (abs(a[x][j])>eps) va[++t]=j; to[ch][cur] = cur_node++; 6.3 Palindromic Tree
} }
for1(i,m) if(i!=x&&abs(a[i][y])>eps) { int nxt = to[ch][cur];
k=a[i][y]; pch[nxt] = ch; struct node {
a[i][y]=0; par[nxt] = cur; int len, suff;
b[i]-=k*b[x]; dep[nxt] = dep[cur] + 1; int to[2]; // size of the alphabet
for1(j,t) a[i][va[j]]-=k*a[x][va[j]]; cur = nxt;
} } node() {
k=c[y]; term[cur] = true; to[0] = to[1] = -1;
c[y]=0; } suff = -1;
v+=k*b[x]; len = -1;
for1(j,t) c[va[j]]-=k*a[x][va[j]]; int get_suff(int node) { }
} if (node == 0) return 0;
if (par[node] == 0) return 0; } T[N];
LD x[ N ]; if (suff[node] != -1) return suff[node]; int size = 2; // 0 -> -1 | 1 -> e
LD ans; int maxPal = 0;
int solve() { int ret = get_go(pch[node], get_suff(par[node])); char st[N], ans[N];
for1(i,n) Down[i]=i; suff[node] = ret;
for1(i,m) Left[i]=n+i; return ret; bool addChar(int i, int c) {
while(1) { } bool ret = false;
int x=0; while (true) {
for1(i,m) if (b[i]<-eps&&(x==0||b[i]<b[x int get_go(int ch, int node) { int curLen = T[maxPal].len;
])) x=i; if (to[ch][node] != -1) return to[ch][node]; if (st[i] == st[i - curLen - 1]) {
if(x==0) break; if (go[ch][node] != -1) return go[ch][node]; int v;
int y=0; if (node == 0) return 0; if (T[maxPal].to[c] == -1) {
for1(j,n) if (a[x][j]<-eps) if (y==0||a[x int ret = get_go(ch, get_suff(node)); v = size++;
][j]<a[x][y]) y=j; go[ch][node] = ret; T[maxPal].to[c] = v;
if(y==0) { return -1; } //Infeasible return ret; T[v].len = curLen + 2;
pivot(x,y); } ret = true;
} }
while(1) { void calc_term() { else v = T[maxPal].to[c];
int y=0;
for1(i,n) if (c[i]>eps&&(y==0||c[i]>c[y]) vector<pair<int, int> > mas; if (T[v].len == 1) T[v].suff = 1;
) y=i; FOR(i, cur_node) { else {
if(y==0) break; mas.pb(mp(dep[i], i)); while (true) {
int x=0; } maxPal = T[maxPal].suff;
for1(j,m) if (a[j][y]>eps) if (x==0||b[j sort(all(mas)); if (st[i] == st[i - T[maxPal].len - 1]) {
]/a[j][y]<b[x]/a[x][y]) x=j; for (auto p : mas) { T[v].suff = T[maxPal].to[c];
if(x==0) { return -2; } // Unbounded int i = p.second; break;
pivot(x,y); next_term[i] = -1; }
} int to = get_suff(i); }
ans = v; if (term[to]) next_term[i] = to; }
for1(i,m) if(Left[i]<=n) idx[Left[i]]=i; else next_term[i] = next_term[to]; maxPal = v;
for1(i,n) x[i] = b[idx[i]]; } break;
13
return 1; }
} for (auto p : mas) { maxPal = T[maxPal].suff;
Yerevan State University
} } i = (i + (1 << h)) % n;
return ret; } j = (j + (1 << h)) % n;
} len -= (1 << h);
void build_sparse_table() { }
mlog[1] = 0; return 0;
// init for (int i = 2; i < N; ++i) mlog[i] = 1 + mlog[i >> 1]; }
T[1].len = 0; FOR(i, n - 1) mini[0][i] = lcp[i];
T[1].suff = 0; // e -> "-1" FOR(h, LOG - 1) {
FOR(i, n - 1) {
if (i + (1 << (h + 1)) > n - 1) break;
}
mini[h + 1][i] = min(mini[h][i], mini[h][i + (1 << h)]); 6.7 Suffix Tree
6.4 Prefix Function }
}
const int N = 300007;
char A[N], B[N], C[N], S[N];
p[0] = 0; int get_min(int i, int j) { int na, nb, nc, n;
for (int i = 1; i < n + m + 1; i++) { if (i == j) return N;
int pos = p[i - 1]; --j; struct node {
while (pos>0 && s[pos] != s[i]) pos = p[pos - 1]; int k = mlog[j - i + 1]; int l, r, par, suff;
if (s[pos] == s[i]) pos++; return min(mini[k][i], mini[k][j - (1 << k) + 1]); char pch;
p[i] = pos; } map<char, int> nxt;
}
node(int l = 0, int r = 0, int par = 0, char pch = 0, int suff
= -1) :
l(l), r(r), par(par), pch(pch), suff(suff) {
6.6 Suffix Array (Implementation 2) }
6.5 Suffix Array (Implementation 1) int len() const {
return r - l;
const int N = 100007; }
const int N = 20007; const int A = 256; } T[2 * N];
const int LOG = 16; char st[N];
char st[N]; int n; struct pos {
int n; int v, p;
int cnt[N], p[N], tp[N], c[N], tc[N]; struct SA { pos(int v = 0, int p = 0) : v(v), p(p) {}
int lcp[N], mlog[N], mini[LOG][N]; } ptr;
int C[20][N], p[N], tp[N], cnt[N]; int size = 1;
void build() {
FOR(i, n) ++cnt[st[i]]; void build() { pos go(const pos &ptr, char c) {
FOR(i, N) { FOR(i, A) cnt[i] = 0; if (T[ptr.v].len() == ptr.p) {
if (i) cnt[i] += cnt[i - 1]; FOR(i, n) ++cnt[st[i]]; int v = ptr.v;
} FOR(i, A) { if (T[v].nxt.count(c)) {
for (int i = n - 1; i >= 0; --i) { if (i) cnt[i] += cnt[i - 1]; int to = T[v].nxt[c];
p[--cnt[st[i]]] = i; } return pos(to, 1);
} for (int i = n - 1; i >= 0; --i) { }
c[p[0]] = 0; p[--cnt[st[i]]] = i; return pos(-1, -1);
for (int i = 1, cur = 0; i < n; ++i) { } }
if (st[p[i]] != st[p[i - 1]]) ++cur; C[0][p[0]] = 0; if (S[T[ptr.v].l + ptr.p] == c) return pos(ptr.v, ptr.p + 1);
c[p[i]] = cur; for (int i = 1, cur = 0; i < n; ++i) { return pos(-1, -1);
} if (st[p[i]] != st[p[i - 1]]) ++cur; }
for (int h = 0; (1 << h) < n; ++h) { C[0][p[i]] = cur;
FOR(i, n) { } int split(const pos &ptr) {
tp[i] = p[i] - (1 << h); for (int h = 1, lev = 0; h < n; h <<= 1, ++lev) { if (T[ptr.v].len() == ptr.p) return ptr.v;
if (tp[i] < 0) tp[i] += n; FOR(i, n) tp[i] = (p[i] - h + n) % n; if (ptr.p == 0) return T[ptr.v].par;
} FOR(i, n) cnt[i] = 0;
FOR(i, n) ++cnt[C[lev][i]]; int mid = size++;
memset(cnt, 0, sizeof cnt); FOR(i, n) { int v = ptr.v;
FOR(i, n) ++cnt[c[i]]; if (i) cnt[i] += cnt[i - 1]; int par = T[v].par;
FOR(i, N) { } char midch = S[T[v].l + ptr.p];
if (i) cnt[i] += cnt[i - 1]; for (int i = n - 1; i >= 0; --i) {
} int ind = tp[i]; //par
for (int i = n - 1; i >= 0; --i) { p[--cnt[C[lev][ind]]] = ind; T[par].nxt[T[v].pch] = mid;
p[--cnt[c[tp[i]]]] = tp[i]; }
} //mid
C[lev + 1][p[0]] = 0; T[mid].par = par;
tc[p[0]] = 0; for (int i = 1, cur = 0; i < n; ++i) { T[mid].pch = T[v].pch;
for (int i = 1, cur = 0; i < n; ++i) { if (C[lev][p[i - 1]] != C[lev][p[i]] || C[lev][(p[i - T[mid].l = T[v].l;
int m1 = (p[i] + (1 << h)) % n; 1] + h) % n] != C[lev][(p[i] + h) % n]) ++cur; T[mid].r = T[v].l + ptr.p;
int m2 = (p[i - 1] + (1 << h)) % n; C[lev + 1][p[i]] = cur; T[mid].nxt[midch] = v;
if (c[p[i]] != c[p[i - 1]] || c[m1] != c[m2]) ++cur; }
tc[p[i]] = cur; } // v
} } T[v].par = mid;
FOR(i, n) c[i] = tc[i]; } sa; T[v].pch = midch;
} T[v].l = T[mid].r;
} int getlcp(int i, int j) {
int ans = 0; return mid;
void calc_lcps() { for (int h = 19; h >= 0; --h) { }
int *pos = new int[n]; if ((1 << h) > n) continue;
FOR(i, n) pos[p[i]] = i; if (sa.C[h][i] == sa.C[h][j]) { pos fastGo(pos ptr, int l, int r) {
int cur = 0; i += (1 << h); while (l != r) {
FOR(i, n) { j += (1 << h); if (T[ptr.v].len() == ptr.p) {
int ind = pos[i]; ans += (1 << h); ptr.v = T[ptr.v].nxt[S[l]];
if (ind == n - 1) { } ++l;
cur = 0; } ptr.p = 1;
continue; return ans; continue;
} } }
cur = max(0, cur - 1); int step = min(T[ptr.v].len() - ptr.p, r - l);
while (p[ind] + cur < n && p[ind + 1] + cur < n && st[p[ind int compare(int i, int j, int len) { ptr.p += step;
] + cur] == st[p[ind + 1] + cur]) { for (int h = 19; h >= 0; --h) { l += step;
++cur; if ((1 << h) > len) continue; }
14
} if (sa.C[h][i] < sa.C[h][j]) return -1; if (ptr.p == 0) {
lcp[ind] = cur; if (sa.C[h][i] > sa.C[h][j]) return 1; ptr.p = T[ptr.v].len();
Yerevan State University
ptr.v = T[ptr.v].par; n = (int)s.size(); {
} z.resize(n, 0); int i = g1[u].i;
return ptr; z[0] = 0; if(i-r!=g1[u].d)
} for (i = 1; i < n; i++) { {
if (r >= i) { g2.push_back( triple(i, i-r, 1) )
pos getSuff(int v) { z[i] = min(z[i - l], r - i + 1); ;
if (T[v].suff != -1) return pos(T[v].suff, T[T[v].suff].len()) } if(g1[u].k > 1)
; while (z[i] + i < n && s[z[i] + i] == s[z[i]]) z[i]++; g2.push_back( triple(i+g1
pos ret; if (i + z[i] - 1 > r) { [u].d, g1[u].d, g1[
if (T[v].par == 0) ret = fastGo(0, T[v].l + 1, T[v].r); l = i; u].k-1) );
else ret = fastGo(getSuff(T[v].par), T[v].l, T[v].r); r = i + z[i] - 1; }
assert(ret.p == T[ret.v].len()); } else
T[v].suff = ret.v; } g2.push_back( g1[u] );
return ret; r = i+(g1[u].k-1)*g1[u].d;
} }
if(j > 1 && s[j-1]==s[j])
void extend(int i) { {
char c = S[i];
while (true) {
6.9 All Palindroms g2.push_back( triple(j-1, j-1-r, 1) );
r = j-1;
pos goPos = go(ptr, c); }
if (goPos.v == -1) { const int K = 30; g2.push_back( triple(j, j-r, 1) );
int mid = split(ptr); typedef long long LL;
int leaf = size++; inline LL F(LL x) g.clear();
T[mid].nxt[c] = leaf; { triple tr = g2[0];
T[leaf] = node(i, n, mid, c); if(x&(1ll<<(K+1))) for(int u = 1; u < (int)g2.size(); ++ u)
if (ptr.v == 0) { return xˆ(1ll<<(K+1)); {
ptr = pos(0, 0); return x; if(tr.d==g2[u].d)
break; } tr.k+=g2[u].k;
} struct all_palind else
int par = T[mid].par; { {
if (par == 0) ptr = fastGo(pos(0, 0), T[mid].l + 1, T[ static const int N = 3*100000+5; g.push_back( tr );
mid].r); LL pl[ N ]; tr = g2[u];
else ptr = fastGo(getSuff(par), T[mid].l, T[mid].r); LL gpl[ N ]; }
} int n; }
else { char s[ N ]; g.push_back( tr );
ptr = goPos; struct triple
break; { for(int u = 0; u < (int)g.size(); ++ u)
} int i, d, k; {
} triple(int _i = 0,int _d = 0,int _k = 0):i(_i), d int i = g[u].i, d = g[u].d;
} (_d), k(_k){} int r = i+(g[u].k-1)*d;
}; LL m = pl[ r - 1 ];
void print(int u) { vector< triple > g; if(g[u].k > 1)
for (auto p : T[u].nxt) { void init(int _n) m = m|gpl[ i-d ];
int to = p.second; { if(d <= i)
cerr << "edge from " << u << " " << " to " << to << " by n = _n; gpl[ i-d ] = m;
string " << string(S + T[to].l, S + T[to].r) << endl; } pl[j]|=m;
print(to); void phase(int j) }
} { pl[j] = F(pl[j]<<1);
} vector< triple > g1; if(g[0].i==1)
for(int u = 0; u < (int)g.size(); ++ u) pl[j]|=1;
// build { }
T[0].suff = 0; int i = g[u].i; };
for (int i = 0; i < n; ++i) extend(i); if(i > 1 && s[i-1]==s[j])
g1.push_back( triple(g[u].i-1, g[
u].d, g[u].k) );
}
vector< triple > g2;
6.8 Z Function int r = -j;
for(int u = 0; u < (int)g1.size(); ++ u)
15