0% found this document useful (0 votes)
17 views15 pages

Notebook

The document is a technical notebook from Yerevan State University focused on dynamic programming and data structures, detailing various algorithms and optimization techniques. It includes sections on the Convex Hull Trick, Knuth Optimization, and various data structures like segment trees and graphs. The content is structured with code snippets and mathematical formulations relevant to competitive programming and algorithm design.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
17 views15 pages

Notebook

The document is a technical notebook from Yerevan State University focused on dynamic programming and data structures, detailing various algorithms and optimization techniques. It includes sections on the Convex Hull Trick, Knuth Optimization, and various data structures like segment trees and graphs. The content is structured with code snippets and mathematical formulations relevant to competitive programming and algorithm design.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Yerevan State University

6.9 All Palindroms . . . . . . . . . . . . . . . . 15 uxix u, v;


Yerevan State University ACM ICPC u = mas[top-1];
v = mas[top-2];
assert(k >= u.k);
Team Notebook 1 Dynamic Programming assert(u.k >= v.k);
if ((LD)(v.b - u.b) / (u.k - v.k) > (LD)(u.b - b) /
(k - u.k))
--top;

Contents 1.1 Convex Hull Trick


}
else
break;

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;

1.4 Knuth Optimization (Type 1) int tm = (tl + tr) / 2;


if (x <= tm) extUpdate(T->l, tl, tm, x, y, val);
2.1 2D Dynamic Segment Tree else extUpdate(T->r, tm + 1, tr, x, y, val);
intUpdate(T->root, 0, N, y, val, true, T->l ? T->l->root :
// dp[i][j] = Min_{k < j}{dp[i-1][k] + cost(k, j)} NULL, T->r ? T->r->root : NULL);
// if opt[i-1][j] <= opt[i][j] <= opt[i][j+1] struct intNode { }
intNode *l, *r;
int dp[N][N]; int tl, tr;
int opt[N][N]; LL g;

int cost(int l, int r) {


// ...
intNode(int tl = 0, int tr = 0, LL g = 0, intNode *l = NULL,
intNode *r = NULL):
2.2 Centroid Decomposition
} tl(tl), tr(tr), g(g), l(l), r(r) { }
};
void solve() { typedef intNode* intPnode; const int N = 1000007;

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 &LT, 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;

return ret; void rotate(node n){


} node p = n->p;
const int N = 1000007; node g = p->p;
struct node { int getSize(pnode T) { bool t = Type(n);
int pr, size; return T ? T->size : 0; connect(t?n->l:n->r,p,t);
int val; } if(!is_root(p))
node *l, *r; connect(n,g,Type(p));
void fix(pnode T) { else
node(int pr = 0, int val = 0, node *l = NULL, node *r = NULL) if (T) T->size = 1 + getSize(T->l) + getSize(T->r); n->p = g;
: } connect(p,n,tˆ1);
pr(pr), l(l), r(r), size(1), val(val) { update(p);
} void push(pnode &T) { update(n);
} *root; if (!T->rev) return; }
typedef node* pnode; T->l = copyNode(T->l); stack< node > st;
int cur, prio[N]; T->r = copyNode(T->r); void splay(node n){
swap(T->l, T->r); node u = n;
inline int getSize(pnode T) { T->rev = false; while(1){
return (T ? T->size : 0); if (T->l) T->l->rev ˆ= 1; st.push( u);
} if (T->r) T->r->rev ˆ= 1; if(is_root(u))
} break;
inline void fix(pnode &T) { u = u->p;
if (!T) { void split(pnode T, int cnt, pnode &L, pnode &R) { }
return; if (!T) { while(!st.empty()){
} L = R = NULL; push(st.top());st.pop();
T->size = getSize(T->l) + getSize(T->r) + 1; return; }
} } while(!is_root(n)){
pnode cur = copyNode(T); node p = n->p;
void merge(pnode A, pnode B, pnode &T) { push(cur); if(!is_root(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 } }

pt normalize() const { vector<plane> faces;


return *this * (1.0 / len()); FOR(i, 4) FOR(j, i) FOR(k, j) {
int get(int x, int y){ } faces.pb(plane(i, j, k));
if (x <= 0 || y <= 0) }
return 0; pt to_len(LD need_len) const {
int val = mul(Q.get(x, y), mul(x + 1, y + 1)) + Fij.get(x return this->normalize() * need_len; pt O = (p[0] + p[1] + p[2] + p[3]) / 4.0; // point strictly
, y) - mul(Fi.get(x, y), y + 1) - mul(Fj.get(x, y), } inside
x + 1);
return (val%MO + MO) % MO; bool operator < (const pt &o) const { for (int ptr = 4; ptr < n; ++ptr) {
} if (fabsl(x-o.x) > eps) return x < o.x; auto P = p[ptr];
void update(int x, int y,int val){ if (fabsl(y-o.y) > eps) return y < o.y; if (inside(P, faces, O)) continue;
if (x > n || y > m) return z < o.z - eps;
return; } vector<plane> new_faces;
// cout << x << " " << y<<" "<<val << endl; }; vector<plane> to_delete;
Q.update(x, y, val);
Fi.update(x, y, mul(val,x)); LD det(LD a, LD b, LD c, LD d) { FOR(i, sz(faces)) {
Fj.update(x, y, mul(val,y)); return a*d - b*c; int need_sign = sign(dist_from_plane(O, faces[i]));
Fij.update(x, y, mul(val, mul(x, y))); } int cur_sign = sign(dist_from_plane(P, faces[i]));
} if (cur_sign * need_sign != -1) {
void add_val(int sx, int sy, int fx, int fy, int val){//val==1 LD dot(pt u, pt v) { new_faces.pb(faces[i]);
update(sx, sy, val); return u.x * v.x + u.y * v.y + u.z * v.z; }
update(sx, fy+1, (MO-val)%MO); } else {
update(fx+1, sy , (MO-val)%MO); to_delete.pb(faces[i]);
update(fx + 1, fy+1, val); pt cross(pt u, pt v) { }
} return pt(det(u.y, u.z, v.y, v.z), }
int get_sum(int sx, int sy, int fx, int fy){ -det(u.x, u.z, v.x, v.z),
//cout << sx<<" "<<sy<<" "<<fx<<" "<<fy<<" "<<Q.get(fx, det(u.x, u.y, v.x, v.y)); unordered_map<int, int> M;
fy) << endl; }
int val = get(fx, fy) - get(sx - 1, fy) - get(fx, sy - 1) for (auto t : to_delete) {
+ get(sx - 1, sy - 1); vector<pt> p; int i = t.i;
val = (val%MO + MO) % MO; int j = t.j;
return val; struct plane { int k = t.k;
} LD a, b, c, d; M[min(i, j) * N + max(i,j)] += 1;
pt A, B, C; M[min(i, k) * N + max(i,k)] += 1;
int i, j, k; M[min(k, j) * N + max(k,j)] += 1;
}
plane(LD a=0, LD b=0, LD c=0, LD d=0): a(a), b(b), c(c), d(d)

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;
} } }

pt prod(LD c) const { pt operator - (const pt &o) const { pt bmax = B[0];


return pt(c*x, c*y); return pt(x-o.x, y-o.y); for (auto P : B) {
} } if (dot(P, dir) < dot(bmax, dir)) bmax = P;
}
bool operator < (const pt &o) const { } p[N];
static const LD eps=1e-5; int n; if (amax.x < bmax.x) cur = amax;
if (fabsl(x-o.x) > eps) return x < o.x; else cur = bmax;
return y < o.y - eps; struct Plane {
} LD a, b, c; FOR(i, iter+1) {
int s; if (get_sign(cur, planes[i]) == -planes[i].s)
} hull[N]; return false;
int n, nhull; Plane(LD aa=0, LD bb=0, LD cc=0, int s=0): s(s) { }
LD norm = sqrtl(aa*aa+bb*bb); }
LD cross(pt u, pt v) { a = aa / norm; }
return u.x * v.y - u.y * v.x; b = bb / norm;
} c = cc / norm; return true;
} }
LD dot(pt u, pt v) { };
return u.x * v.x + u.y * v.y; } hp;
} LD dot(pt u, pt v) {
return u.x * v.x + u.y * v.y;
bool ccw(pt A, pt B, pt C) { } bool check(int k) {
static const LD eps = 1e-5; hp.init();
return cross(B-A, C-B) > eps; LD sign(LD x) { FOR(i, n) {
} if (x < -eps) return -1; int j=(i+k)%n;
if (x > +eps) return 1;
void convex_hull(pt *A, int n) { return 0; LD a = p[i].y - p[j].y;
// build convex hull, write answer in (hull, nhull) } LD b = p[j].x - p[i].x;
} LD c = -a * p[i].x - b * p[i].y;
int get_sign(pt A, Plane p) {
LD dist_from_line(pt A, pt B, pt C) { return sign(p.a * A.x + p.b * A.y + p.c); int z=(i-1+n)%n;
pt u = B-A; } int s = sign(a*p[z].x + b*p[z].y + c);
swap(u.x, u.y);
u.x = -u.x; struct HalfPlaneIntersection { hp.add(Plane(a, b, c, s));
return fabsl(dot(u, C-A)); }
} vector<Plane> planes; return hp.check();
}
LD get_distance(pt *A, int n) { void init() {
convex_hull(A, n); planes.clear();
planes.resize(0);
LD ret = 0.0; }
int n = nhull;
pt *A = hull; void add(Plane p) {
3.6 Minkowski Sum of Convex Poly-
if (n <= 3) {
if (p.s == 1) {
p.c -= eps; gons
FOR(i, n) FOR(j, i) { }
ret = max(ret, A[i].dist(A[j])); else {
} p.c += eps; const LD pi = acosl(-1.0);
return ret; } const LD eps = 1e-11;
} planes.pb(p); const int N = 250007;
}
int r = 1; #define vect pt
while(dist_from_line(A[0], A[1], A[(r+1)%n]) > dist_from_line bool check() { struct pt {
(A[0], A[1], A[r])) r = (r+1) % n; random_shuffle(all(planes)); LL x, y;
ret = max(ret, A[r].dist(A[0])); planes.pb(Plane(1, 0, INF, 1)); pt() : x(0), y(0) { }
planes.pb(Plane(1, 0, -INF, -1)); pt(LL x, LL y) : x(x), y(y) {}
for (int i = 1; i < n; ++i) { planes.pb(Plane(0, 1, INF, 1));
while(dist_from_line(A[i], A[(i+1)%n], A[(r+1)%n]) > planes.pb(Plane(0, 1, -INF, -1)); pt operator + (const pt &o) const {
dist_from_line(A[i], A[(i+1)%n], A[r])) r = (r+1) % reverse(all(planes)); return pt(x + o.x, y + o.y);
n; }
ret = max(ret, A[r].dist(A[i])); pt cur(-INF, 0);
} for (int iter = 4; iter < sz(planes); ++iter) { pt operator - (const pt &o) const {
return ret; auto p = planes[iter]; return pt(x - o.x, y - o.y);
} }
if (get_sign(cur, p) == -p.s) {
pt dir = pt(-p.b, p.a); bool operator < (const pt &o) const {
vector<pt> A, B; if (x != o.x) return x < o.x;
return y < o.y;
3.5 Half Plane Intersection (Random- FOR(i, iter) {
auto q = planes[i];
}

ized Incremental Algorithm) LD det = p.a * q.b - p.b * q.a;


LD len() const {
return sqrtl((LD)x * x + (LD)y * y);
if (fabsl(det) < eps) continue; }
LD detx = q.c * p.b - p.c * q.b;
const LD eps = 1e-8; LD dety = p.c * q.a - q.c * p.a; pt rotate() const {
pt X = pt(detx/det, dety/det); return pt(y, -x);
struct pt { }
LD x, y; if (get_sign(X + dir, q) == q.s) { };
pt (LD x=0, LD y=0): x(x), y(y) { A.pb(X); vector<pt> mas[N];
} } LL ans = 0;
else {
void read() { B.pb(X); LD get_angle(LD ux, LD uy, LD x, LD y) {
int a, b; } LD l1 = sqrtl(ux * ux + uy * uy);
scanf("%d%d", &a, &b); } LD l2 = sqrtl(x * x + y * y);
x=a; if (l1 < eps || l2 < eps) return 2 * pi;
y=b; // A and B are not empty (note 4 initial half LD t = (ux * x + uy * y) / l1 / l2;

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;

vect ua = vect(A[nposa].x - A[posa].x, A[nposa].y - A[ // main


posa].y).rotate(); scanf("%d", &n);
vect ub = vect(B[nposb].x - B[posb].x, B[nposb].y - B[ const LD pi = acosl(-1.0); for (int i = 0; i < n; ++i) {
posb].y).rotate(); const LD eps = 1e-7; int ax, ay, bx, by;
struct pt { scanf("%d%d%d%d", &ax, &ay, &bx, &by);
if (na == 3 && nb == 2 && rot > 0) { LD x, y; seg.pb(mp(pt(ax, ay), pt(bx, by)));
cerr << ua.x << " " << ua.y << " " << cosl(rot) << pt(LD x = 0.0, LD y = 0.0) : x(x), y(y) {} }
sinl(rot) << endl;
} void rotate(LD ang) { while (true) {
LD anga = get_angle(0.0 + ua.x, 0.0 + ua.y, cosl(rot), LD fi = atan2l(y, x); LD rotAngle = rand() / (LD)RAND_MAX * 2.0 * pi;
sinl(rot)); LD len = sqrtl(x * x + y * y); bool ok = true;
LD angb = get_angle(0.0 + ub.x, 0.0 + ub.y, cosl(rot), fi += ang; for (int i = 0; i < n; ++i) {
sinl(rot)); x = len * cosl(fi); seg[i].first.rotate(rotAngle);
y = len * sinl(fi); seg[i].second.rotate(rotAngle);
if (anga < angb) { } if (fabsl(seg[i].first.x - seg[i].second.x) < eps) {
rot += anga; }; ok = false;
posa = nposa; vector<pair<pt, pt> > seg; break;
} int n; }
else { }
rot += angb; bool inSegment(pt &M, pt &A, pt &B) { if (ok) break;
posb = nposb; return min(A.x, B.x) < M.x + eps && M.x < max(A.x, B.x) + eps }
} && vector<pair<LD, int> > events;
if (rot > 2 * pi - eps) break; min(A.y, B.y) < M.y + eps && M.y < max(A.y, B.y) + eps;
C[nc++] = A[posa] + B[posb]; } for (int i = 0; i < n; ++i) {
} if (seg[i].first.x > seg[i].second.x) swap(seg[i].first, seg[i
} bool intersects(LD a, LD b, LD c, LD d) { ].second);
if (a > b) swap(a, b);
pt tmp[N], H[N]; if (c > d) swap(c, d); events.pb(mp(seg[i].first.x, -i - 1));
pt A[N], B[N], C[N]; return max(a, c) < min(b, d) + eps; events.pb(mp(seg[i].second.x, +i + 1));
int na, nb, nc; } }
sort(all(events));
LL cross(vect a, vect b) { bool intersects(pt &A, pt &B, pt &C, pt &D) { for (int i = 0; i < 2 * n; ++i) {
return a.x * b.y - a.y * b.x; LD a1 = A.y - B.y; int ty = events[i].second;
} LD b1 = B.x - A.x; sweepX = events[i].first;
LD c1 = -a1 * A.x - b1 * A.y; if (ty < 0) // open
bool ccw(pt A, pt B, pt C) { {
return cross(B - A, C - B) > 0; LD a2 = C.y - D.y; int id = -ty - 1;
} LD b2 = D.x - C.x; auto it = status.lower_bound(segment(id));
LD c2 = -a2 * C.x - b2 * C.y; if (it != status.begin()) {
void convex_hull(int &na, pt *A) { auto oit = it;
if (na <= 2) return; LD det = a1 * b2 - a2 * b1; --oit;
int nh = 0; if (intersects(oit->id, id)) {
sort(A, A + na); if (fabsl(det) < eps) { printf("YES\n%d %d\n", id + 1, oit->id + 1);
int ptr = 0; if (fabsl(c1 * b2 - c2 * b1) < eps && fabsl(c1 * a2 - c2 * return 0;
FOR(i, na) { a1) < eps) }
while (ptr >= 2 && !ccw(tmp[ptr - 2], tmp[ptr - 1], A[i]) return intersects(A.x, B.x, C.x, D.x) && intersects(A.y, }
) --ptr; B.y, C.y, D.y); if (it != status.end() && intersects(id, it->id)) {
tmp[ptr++] = A[i]; return false; printf("YES\n%d %d\n", id + 1, it->id + 1);
} } return 0;
FOR(i, ptr - 1) H[nh++] = tmp[i]; else { }
ptr = 0; pt M; status.insert(segment(id));
for (int i = na - 1; i >= 0; --i) { M.x = (b1 * c2 - b2 * c1) / det; }
while (ptr >= 2 && !ccw(tmp[ptr - 2], tmp[ptr - 1], A[i]) M.y = (a2 * c1 - a1 * c2) / det; else // close
) --ptr; return inSegment(M, A, B) && inSegment(M, C, D); {
tmp[ptr++] = A[i]; } int id = ty - 1;
} } auto it = status.lower_bound(segment(id));
FOR(i, ptr - 1) H[nh++] = tmp[i]; if (it != status.begin() && it != status.end()) {
na = nh; inline bool intersects(int i, int j) { auto lit = it; --lit;
FOR(i, na) A[i] = H[i]; return intersects(seg[i].first, seg[i].second, seg[j].first, auto rit = it; ++rit;
} seg[j].second); if (rit != status.end() && intersects(lit->id, rit->id))
} {
void solvefor(int l, int r) { printf("YES\n%d %d\n", lit->id + 1, rit->id + 1);
if (l == r) return; LD sweepX; return 0;
struct segment { }
int m = (l + r) / 2; int id; }
solvefor(l, m); segment(int id = 0) : id(id) {} status.erase(segment(id));
solvefor(m + 1, r); bool operator < (const segment &o) const { }
pt& A = seg[id].first; }
na = 0; pt& B = seg[id].second; puts("NO");

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 }
}
]]);

for (int i = 1; i < N; ++i) { }


if (lp[i] == i) invf[i] = inv(i);
else invf[i] = invf[i / lp[i]] * invf[lp[i]] % MOD; 6.1 Aho-Corasick } ac;
}
invf[0] = 1;
for (int i = 1; i < N; ++i) { int code(char ch) {
invf[i] = invf[i] * invf[i-1] % MOD; if (ch >= ’a’ && ch <= ’z’) return ch - ’a’;

}
} 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

You might also like