100% found this document useful (1 vote)
1K views42 pages

Algorithm Cheat Sheet

This document provides a detailed table of contents for a notebook on algorithms and data structures. It includes sections on topics like sorting and searching, graphs, dynamic programming, strings, trees, range queries, and mathematics. Each section lists various related techniques and data structures like binary search trees, suffix arrays, segment trees, and matrix exponentiation with brief explanations and running times.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
100% found this document useful (1 vote)
1K views42 pages

Algorithm Cheat Sheet

This document provides a detailed table of contents for a notebook on algorithms and data structures. It includes sections on topics like sorting and searching, graphs, dynamic programming, strings, trees, range queries, and mathematics. Each section lists various related techniques and data structures like binary search trees, suffix arrays, segment trees, and matrix exponentiation with brief explanations and running times.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 42

6.3.4 Lazy SegTree (4) . . . . . . . . . . . .

10
6.3.5 Sparse SegTree (4) . . . . . . . . . . . 11
6.3.6 SegTree Beats (6) . . . . . . . . . . . 12
6.4 2D Range Queries (4) . . . . . . . . . . . . . 13
USACO Notebook: Complete 6.4.1 2D BIT . . . . . . . . . . . . . . . . . 13
6.4.2 2D SegBIT . . . . . . . . . . . . . . . 13
Benq 6.4.3 2D SegTree . . . . . . . . . . . . . . . 13
6.4.4 Merge-Sort Tree . . . . . . . . . . . . 14
February 27, 2018 6.5 BBST (4) . . . . . . . . . . . . . . . . . . . . 14
6.5.1 Treap . . . . . . . . . . . . . . . . . . 14
6.5.2 Link-Cut Tree (5) . . . . . . . . . . . 15
6.5.3 Splay Tree (5) . . . . . . . . . . . . . 16
Contents 6.6 Persistent Queries (5) . . . . . . . . . . . . . 17
6.6.1 Basic Persistent SegTree . . . . . . . . 17
1 Contest 2 6.6.2 Lazy Persistent SegTree . . . . . . . . 18
1.1 C++ Template . . . . . . . . . . . . . . . . . 2 6.6.3 Low-Memory Persistent Segment Tree 19
1.2 FastScanner . . . . . . . . . . . . . . . . . . . 2
1.3 Troubleshooting . . . . . . . . . . . . . . . . . 3 7 DP (3) 19
7.1 Examples . . . . . . . . . . . . . . . . . . . . 19
2 Sorting And Searching (2) 4 7.1.1 Knapsack . . . . . . . . . . . . . . . . 19
2.1 Interval Cover . . . . . . . . . . . . . . . . . 4 7.1.2 Longest Common Subsequence . . . . 19
2.2 Binary Search . . . . . . . . . . . . . . . . . 4 7.1.3 Longest Increasing Subsequence . . . . 19
7.1.4 String Removals . . . . . . . . . . . . 20
3 Data Structures (2) 4 7.1.5 Traveling Salesman (4) . . . . . . . . . 20
3.1 Set . . . . . . . . . . . . . . . . . . . . . . . 4 7.2 Divide And Conquer (4) . . . . . . . . . . . 20
3.1.1 Coordinate Compression . . . . . . . . 4
3.1.2 Map Customization . . . . . . . . . . 5 8 Strings (3) 20
8.1 Hashing . . . . . . . . . . . . . . . . . . . . . 20
4 Graphs Easy (2) 5 8.2 Bitset Trie (4) . . . . . . . . . . . . . . . . . 21
4.1 Traversal . . . . . . . . . . . . . . . . . . . . 5 8.3 Suffix Array (4) . . . . . . . . . . . . . . . . 21
4.1.1 BFS on Grid . . . . . . . . . . . . . . 5 8.3.1 Suffix Array . . . . . . . . . . . . . . 21
4.1.2 DFS on Graph . . . . . . . . . . . . . 5 8.3.2 Reverse Burrows-Wheeler (6) . . . . . 22
4.2 Shortest Path (3) . . . . . . . . . . . . . . . 5 8.4 Z (5) . . . . . . . . . . . . . . . . . . . . . . 22
4.2.1 Bellman-Ford . . . . . . . . . . . . . . 5 8.4.1 Aho-Corasick . . . . . . . . . . . . . . 22
4.2.2 Dijkstra . . . . . . . . . . . . . . . . . 6 8.4.2 Manacher . . . . . . . . . . . . . . . . 23
4.2.3 Floyd-Warshall . . . . . . . . . . . . . 6 8.4.3 Minimum Rotation . . . . . . . . . . . 23
4.3 Topological Sort (3) . . . . . . . . . . . . . . 6 8.4.4 Z . . . . . . . . . . . . . . . . . . . . . 24
4.4 Kruskal (3) . . . . . . . . . . . . . . . . . . . 7
9 Trees (4) 24
5 Algorithm Design (2) 7 9.1 Tree Diameter . . . . . . . . . . . . . . . . . 24
5.1 Minimum Deque (3) . . . . . . . . . . . . . . 7 9.2 Queries . . . . . . . . . . . . . . . . . . . . . 24
5.2 Ternary Search (4) . . . . . . . . . . . . . . . 7 9.2.1 Heavy-Light Set . . . . . . . . . . . . 24
9.2.2 LCA Demo . . . . . . . . . . . . . . . 25
6 Range Queries (2) 7 9.2.3 LCA with Binary Jumps . . . . . . . . 25
6.1 Static Array Queries . . . . . . . . . . . . . . 7 9.2.4 LCA with RMQ . . . . . . . . . . . . 25
6.1.1 Prefix Sums . . . . . . . . . . . . . . . 7 9.3 Advanced . . . . . . . . . . . . . . . . . . . . 26
6.1.2 Range Minimum Query (3) . . . . . . 8 9.3.1 Centroid Decomposition . . . . . . . . 26
6.1.3 Wavelet Tree (6) . . . . . . . . . . . . 8 9.3.2 Heavy-Light Decomposition . . . . . . 26
6.2 Demos (3) . . . . . . . . . . . . . . . . . . . 9
6.2.1 Point Update Demo . . . . . . . . . . 9 10 Math (4) 27
6.2.2 2D Demo (4) . . . . . . . . . . . . . . 9 10.1 Number Theory . . . . . . . . . . . . . . . . 27
6.2.3 BBST Demo (4) . . . . . . . . . . . . 9 10.1.1 Eratosthenes’ Sieve . . . . . . . . . . . 27
6.2.4 Range Update Demo (4) . . . . . . . . 9 10.1.2 Phi . . . . . . . . . . . . . . . . . . . . 27
6.3 1D Range Queries (3) . . . . . . . . . . . . . 10 10.1.3 CRT (5) . . . . . . . . . . . . . . . . . 27
6.3.1 Binary Indexed Tree . . . . . . . . . . 10 10.2 Matrices . . . . . . . . . . . . . . . . . . . . 28
6.3.2 SegTree . . . . . . . . . . . . . . . . . 10 10.2.1 Matrix Exponentiation . . . . . . . . . 28
6.3.3 BIT with Range Update (4) . . . . . . 10 10.2.2 Gaussian Elimination (6) . . . . . . . 28

1
1. CONTEST 2

10.3 Combinatorics (5) . . . . . . . . . . . . . . . 29 typedef long double ld;


10.3.1 Combo Basic . . . . . . . . . . . . . . 29 typedef vector<int> vi;
10.3.2 Combo Plus . . . . . . . . . . . . . . . 29 typedef pair<int, int> pi;
10.4 FFT (6) . . . . . . . . . . . . . . . . . . . . . 30 typedef vector<pi> vpi;
10.4.1 And Convolution . . . . . . . . . . . . 30 typedef pair<ll,ll> pl;
typedef pair<double,double> pd;
10.4.2 Base Conversion . . . . . . . . . . . . 30
10.4.3 FFT . . . . . . . . . . . . . . . . . . . 31 template <class T> using Tree = tree<T, null_type,
10.4.4 NTT . . . . . . . . . . . . . . . . . . . 32 less<T>,
10.4.5 XOR Convolution . . . . . . . . . . . 32 rb_tree_tag,tree_order_statistics_node_update>;

11 Graphs Hard (4) 33 #define FOR(i, a, b) for (int i=a; i<(b); i++)
11.1 Kosaraju . . . . . . . . . . . . . . . . . . . . 33 #define F0R(i, a) for (int i=0; i<(a); i++)
11.2 Flows . . . . . . . . . . . . . . . . . . . . . . 33 #define FORd(i,a,b) for (int i = (b)-1; i >= a; i--)
11.2.1 Edmonds-Karp . . . . . . . . . . . . . 33 #define F0Rd(i,a) for (int i = (a)-1; i >= 0; i--)
11.2.2 Flows Demo . . . . . . . . . . . . . . . 34
11.2.3 Dinic (5) . . . . . . . . . . . . . . . . 34 #define sz(x) (int)(x).size()
11.2.4 Push-Relabel (5) . . . . . . . . . . . . 35 #define mp make_pair
11.2.5 MinCostFlow (6) . . . . . . . . . . . . 35 #define pb push_back
#define f first
11.3 Tarjan BCC . . . . . . . . . . . . . . . . . . 36
#define s second
11.4 Euler Tour (6) . . . . . . . . . . . . . . . . . 37
#define lb lower_bound
#define ub upper_bound
12 Geometry (4) 37 #define all(x) x.begin(), x.end()
12.1 Techniques . . . . . . . . . . . . . . . . . . . 37
12.1.1 Pair Operators . . . . . . . . . . . . . 37 const int MOD = 1000000007;
12.1.2 Polygon Area . . . . . . . . . . . . . . 38 const double PI = 4*atan(1);
12.1.3 Line Segment Intersection (5) . . . . . 38 const ll INF = 1e18;
12.1.4 Point in Polygon (5) . . . . . . . . . . 38
12.1.5 3D Geometry (6) . . . . . . . . . . . . 39 int main() {
12.1.6 Circles (6) . . . . . . . . . . . . . . . . 39 ios_base::sync_with_stdio(0); cin.tie(0);
12.2 Sweep Line . . . . . . . . . . . . . . . . . . . 39
12.2.1 Convex Hull . . . . . . . . . . . . . . . 39 }
12.2.2 Closest Pair (6) . . . . . . . . . . . . . 40
// read the question correctly (is y a vowel?)
12.2.3 LineContainer (6) . . . . . . . . . . . 40 // look out for special cases (n=1?) and overflow (ll
12.3 Max Collinear . . . . . . . . . . . . . . . . . . 41 vs int?)

13 Additional (4) 41
13.1 Mo . . . . . . . . . . . . . . . . . . . . . . . 41
13.2 Misc . . . . . . . . . . . . . . . . . . . . . . . 41 1.2 FastScanner
13.2.1 Discrete Logarithm . . . . . . . . . . . 41
13.3 Pragma Optimization (6) . . . . . . . . . . . 42 /**
* Source: Matt Fontaine
*/
1 Contest
class FastScanner {
1.1 C++ Template private InputStream stream;
private byte[] buf = new byte[1024];
private int curChar;
/** private int numChars;
* Sources: various
*/ public FastScanner(InputStream stream) {
this.stream = stream;
#include <bits/stdc++.h> }
#include <ext/pb_ds/tree_policy.hpp> int read() {
#include <ext/pb_ds/assoc_container.hpp> if (numChars == -1)
throw new InputMismatchException();
using namespace std; if (curChar >= numChars) {
using namespace __gnu_pbds; curChar = 0;
try {
typedef long long ll; numChars = stream.read(buf);
1. CONTEST 3

} catch (IOException e) { • Are time limits close? If so, generate max cases.
throw new InputMismatchException();
} • Is the memory usage fine?
if (numChars <= 0) return -1;
} • Could anything overflow?
return buf[curChar++]; • Make sure to submit the right file.
}
Wrong answer:
boolean isSpaceChar(int c) {
return c == ’ ’ || c == ’\n’ || c == ’\r’ || c • Print your solution! Print debug output, as well.
== ’\t’ || c == -1;
} • Are you clearing all datastructures between test cases?

boolean isEndline(int c) { • Can your algorithm handle the whole range of input?
return c == ’\n’ || c == ’\r’ || c == -1;
}
• Read the full problem statement again.
• Do you handle all corner cases correctly?
public int nextInt() {
return Integer.parseInt(next()); • Have you understood the problem correctly?
}
• Any uninitialized variables?
public long nextLong() {
return Long.parseLong(next()); • Any overflows?
}
• Confusing N and M, i and j, etc.?
public double nextDouble() { • Are you sure your algorithm works?
return Double.parseDouble(next());
} • What special cases have you not thought of?

public String next() { • Are you sure the STL functions you use work as you
int c = read(); think?
while (isSpaceChar(c)) c = read();
StringBuilder res = new StringBuilder(); • Add some assertions, maybe resubmit.
do {
res.appendCodePoint(c); • Create some testcases to run your algorithm on.
c = read();
• Go through the algorithm for a simple case.
} while (!isSpaceChar(c));
return res.toString(); • Go through this list again.
}
• Explain your algorithm to a team mate.
public String nextLine() {
int c = read(); • Ask the team mate to look at your code.
while (isEndline(c))
c = read(); • Go for a small walk, e.g. to the toilet.
StringBuilder res = new StringBuilder();
• Is your output format correct? (including whitespace)
do {
res.appendCodePoint(c); • Rewrite your solution from the start or let a team mate
c = read(); do it.
} while (!isEndline(c));
return res.toString(); Runtime error:
}
} • Have you tested all corner cases locally?
• Any uninitialized variables?

1.3 Troubleshooting • Are you reading or writing outside the range of any
vector?
Source: KACTL
• Any assertions that might fail?
Pre-submit:
• Any possible division by 0? (mod 0 for example)
• Write a few simple test cases, if sample is not enough.
• Any possible infinite recursion?
2. SORTING AND SEARCHING (2) 4

• Invalidated pointers or iterators? ans.pb(mx.s);

• Are you using too much memory? while (mx.f < B) {


cur = mx.f;
• Debug with resubmits (e.g. remapped signals, see Var- while (nex < in.size() && in[nex].f.f <= cur) {
ious). mx = max(mx,{in[nex].f.s,in[nex].s});
nex++;
Time limit exceeded: }
• Do you have any possible infinite loops? if (mx.f == cur) {
cout << "impossible\n";
• What is the complexity of your algorithm? return;
}
• Are you copying a lot of unnecessary data? (Refer- ans.pb(mx.s);
ences) }
cout << ans.size() << "\n";
• How big is the input and output? (consider scanf) for (int i: ans) cout << i << " ";
cout << "\n";
• Avoid vector, map. (use arrays/unordered map) }
• What do your team mates think about your algorithm?

Memory limit exceeded: 2.2 Binary Search


• What is the max amount of memory your algorithm
should need? /**
* Description: Basic example of binary search
• Are you clearing all data structures between test cases? * Guess the Number
* https://open.kattis.com/problems/guess
*/
2 Sorting And Searching (2)
int main() {
2.1 Interval Cover int lo = 1, hi = 1000;
while (1) {
int mid = (lo+hi)/2;
/** cout << mid << endl;
* Usage: https://open.kattis.com/problems/intervalcover string res; cin >> res;
* Description: Example of greedy algorithm if (res == "correct") return 0;
*/ else if (res == "lower") hi = mid-1;
else lo = mid+1;
double A,B,cur; }
vector<pair<pdd,int>> in; }
int N,nex;
vi ans;

void solve() { 3 Data Structures (2)


nex = 0; ans.clear();
cin >> N; in.resize(N);
F0R(i,N) { 3.1 Set
cin >> in[i].f.f >> in[i].f.s;
3.1.1 Coordinate Compression
in[i].s = i;
}
/**
sort(all(in)); * Description: Demonstrates use of map
pair<double,int> mx = {-DBL_MAX,-1}; * Verification: POI 12 - The Bus
*/
while (nex < in.size() && in[nex].f.f <= A) {
mx = max(mx,{in[nex].f.s,in[nex].s}); void compress(vector<array<int,3>>& x, int ind) {
nex++; map<int,int> m;
} for (auto& a: x) m[a[ind]] = 0;
if (nex == 0) { int co = 0; for (auto& a: m) a.s = co++;
cout << "impossible\n"; for (auto& a: x) a[ind] = m[a[ind]];
return; }
}
4. GRAPHS EASY (2) 5

3.1.2 Map Customization process(todo.front());


todo.pop(); // pop point from queue
}
/**
cout << dist[4][5]; // 11
* Description: Define your own comparator / hash
}
function
* Source: StackOverflow
*/
4.1.2 DFS on Graph
struct cmp {
bool operator()(const int& l, const int& r) const {
/**
return l > r;
* Classic
}
*/
};
int n, visit[100001];
struct hsh {
vi adj[100001];
size_t operator()(const pii& k) const {
return k.f^k.s; // bad, but you get the point
void dfs(int node) {
}
if (visit[node]) return;
};
visit[node] = 1;
for (int i: adj[node]) dfs(i);
set<int,cmp> s;
cout << node << "\n";
map<int,int,cmp> m;
// do stuff
unordered_map<pii,int,hsh> u;
}

int main() {
4 Graphs Easy (2) cin >> n;
F0R(i,n-1) {
4.1 Traversal int a,b; cin >> a >> b;
adj[a].pb(b);
4.1.1 BFS on Grid adj[b].pb(a);
}
/** dfs(1);
* Note: Use xdir and ydir }
*/

int xdir[4] = {0,1,0,-1}, ydir[4] = {1,0,-1,0}; 4.2 Shortest Path (3)


int dist[21][21];
queue<pii> todo; 4.2.1 Bellman-Ford

void process(pii x) {
F0R(i,4) { /**
pii y = {x.f+xdir[i],x.s+ydir[i]}; * Usage: https://open.kattis.com/problems/shortestpath3
if (y.f < 0 || y.f > 20 || y.s < 0 || * Description: can be useful with linear programming
y.s > 20) continue; // ignore this * Constraints of the form x_i-x_j<k
point if it’s outside of grid */
if (dist[y.f][y.s] == MOD) { // test
whether point has been visited or const ll INF = 1e18;
not
dist[y.f][y.s] = dist[x.f][x.s]+1; int n,m,q,s,bad[1000];
todo.push(y); // push point to queue vector<pair<pii,int>> edge;
} ll dist[1000];
}
} void solve() {
edge.clear();
int main() { F0R(i,n) dist[i] = INF, bad[i] = 0;
F0R(i,21) F0R(j,21) dist[i][j] = MOD; dist[s] = 0;
dist[10][10] = 0; todo.push({10,10}); // F0R(i,m) {
initialize queue, distances int u,v,w; cin >> u >> v >> w;
while (todo.size()) { edge.pb({{u,v},w});
}
4. GRAPHS EASY (2) 6

F0R(i,n) for (auto a: edge) if (dist[a.f.f] < INF) * Usage: https://open.kattis.com/problems/allpairspath


dist[a.f.s] = min(dist[a.f.s], */
dist[a.f.f]+a.s);
for (auto a: edge) if (dist[a.f.f] < INF) if const ll INF = 1e18;
(dist[a.f.s] > dist[a.f.f]+a.s) bad[a.f.s] = 1;
F0R(i,n) for (auto a: edge) if (bad[a.f.f]) int n,m,q; // vertices, edges, queries
bad[a.f.s] = 1; ll dist[150][150], bad[150][150];

F0R(i,q) { void solve() {


int x; cin >> x; F0R(i,n) F0R(j,n) dist[i][j] = INF, bad[i][j] = 0;
if (bad[x]) cout << "-Infinity\n"; F0R(i,n) dist[i][i] = 0;
else if (dist[x] == INF) cout << F0R(i,m) {
"Impossible\n"; int u,v,w; cin >> u >> v >> w;
else cout << dist[x] << "\n"; dist[u][v] = min(dist[u][v],(ll)w);
} }
cout << "\n"; F0R(k,n) F0R(i,n) F0R(j,n) if (dist[i][k] != INF
} && dist[k][j] != INF)
dist[i][j] =
min(dist[i][j],dist[i][k]+dist[k][j]);
4.2.2 Dijkstra
F0R(k,n) F0R(i,n) F0R(j,n) if (dist[i][k] != INF
&& dist[k][j] != INF)
/** if (dist[i][j] > dist[i][k]+dist[k][j])
* Description: shortest path! bad[i][j] = 1;
* Works with negative edge weights (aka SPFA?)
*/ F0R(k,n) F0R(i,n) F0R(j,n) {
if (dist[i][k] < INF && bad[k][j]) bad[i][j] =
template<int SZ> struct Dijkstra { 1;
int dist[SZ]; if (bad[i][k] && dist[k][j] < INF) bad[i][j] =
vector<pii> adj[SZ]; 1;
priority_queue<pii,vector<pii>,greater<pii>> q; }

void gen() { F0R(i,q) {


fill_n(dist,SZ,MOD); dist[0] = 0; int u,v; cin >> u >> v;
if (bad[u][v]) cout << "-Infinity\n";
q.push({0,0}); else if (dist[u][v] == INF) cout <<
while (q.size()) { "Impossible\n";
pii x = q.top(); q.pop(); else cout << dist[u][v] << "\n";
if (dist[x.s] < x.f) continue; }
for (pii y: adj[x.s]) if (x.f+y.s < cout << "\n";
dist[y.f]) { }
dist[y.f] = x.f+y.s;
q.push({dist[y.f],y.f});
}
} 4.3 Topological Sort (3)
}
}; /**
* Description: sorts vertices such that if there
Dijkstra<100> D; exists an edge x->y, then x goes before y
*/
int main() {
F0R(i,100) F0R(j,100) if (rand() % 10 == 0) int N,M, in[100001];
D.adj[i].pb({j,rand() % 10+1}); vi res, adj[100001];
D.gen();
F0R(i,100) cout << D.dist[i] << "\n"; void topo() {
} queue<int> todo;
FOR(i,1,N+1) if (in[i] == 0) todo.push(i);
while (sz(todo)) {
4.2.3 Floyd-Warshall int x = todo.front(); todo.pop();
res.pb(x);
for (int i: adj[x]) {
/** in[i] --;
5. ALGORITHM DESIGN (2) 7

if (!in[i]) todo.push(i); 5 Algorithm Design (2)


}
}
} 5.1 Minimum Deque (3)

int main() { /**


cin >> N >> M; * Source: own
F0R(i,M) { * Verification: Jan 18 Lifeguards
int x,y; cin >> x >> y; */
adj[x].pb(y), in[y] ++;
} struct MinDeque {
topo(); int lo = 0, hi = -1;
for (int i: res) cout << i << " "; deque<pii> d;
}
void ins(int x) { // add to back
while (sz(d) && d.back().f >= x) d.pop_back();
d.pb({x,++hi});
4.4 Kruskal (3) }

/** void del() { // delete from front


* Source: own if (d.front().s == lo++) d.pop_front();
* Description: computes the minimum spanning tree in }
O(ElogE) time
* Verification: USACO superbull int get() {
*/ return sz(d) ? d.front().f : MOD;
}
template<int SZ> struct DSU { };
int par[SZ], sz[SZ];
DSU() {
F0R(i,SZ) par[i] = i, sz[i] = 1;
} 5.2 Ternary Search (4)

int get(int x) { // path compression /**


if (par[x] != x) par[x] = get(par[x]); * Description: use on functions which are strictly
return par[x]; decreasing then strictly increasing
} */

bool unite(int x, int y) { // union-by-rank double eval(double x) {


x = get(x), y = get(y); return (x-5)*(x-5);
if (x == y) return 0; }
if (sz[x] < sz[y]) swap(x,y);
sz[x] += sz[y], par[y] = x; double ternary(double l, double r) {
return 1; if (abs(r-l) <= 1e-9) return (l+r)/2;
} double l1 = (2*l+r)/3, r1 = (l+2*r)/3;
}; return eval(l1) < eval(r1) ? ternary(l,r1) :
ternary(l1,r);
int ans = 0; // total weight of MST }
vector<pair<int,pii>> edge;
// ternary(-100,100) = 5
DSU<100> D;

void kruskal() {
sort(all(edge)); 6 Range Queries (2)
for (auto a: edge) if (D.unite(a.s.f,a.s.s))
ans += a.f; // edge is in MST
}
6.1 Static Array Queries
6.1.1 Prefix Sums

/**
* Description: Calculates rectangle sums in constant
time
6. RANGE QUERIES (2) 8

* Verification: POI 16 Ticket Inspector vi revm;


*/
void input() {
template<class T, int SZ> struct sums { cin >> N >> Q;
T sum[SZ][SZ]; F0R(i,N) cin >> A[i];
sums () { memset(sum,0,sizeof sum); } }
void init() {
FOR(i,1,SZ) FOR(j,1,SZ) void compress() {
sum[i][j] += sum[i][j-1] F0R(i,N) m[A[i]] = 0;
+sum[i-1][j]-sum[i-1][j-1]; int nex = 0;
} for (auto& a: m) {
T get(int X1, int X2, int Y1, int Y2) { a.s = nex++;
return sum[X2][Y2]-sum[X1-1][Y2] revm.pb(a.f);
-sum[X2][Y1-1]+sum[X1-1][Y1-1]; }
} F0R(i,N) A[i] = m[A[i]];
}; }

template<int SZ> struct wavelet {


vi mapl[2*SZ], mapr[2*SZ], val[2*SZ];
6.1.2 Range Minimum Query (3)
void build(int ind = 1, int L = 0, int R = SZ-1) {
/** // build a wavelet tree
* Description: Supports 1D range minimum query in if (ind == 1) { F0R(i,N) val[ind].pb(i); }
constant time.
* Verification: Problem Tournament from IOI 2012: if (L < R) {
http://wcipeg.com/problem/ioi1223 int M = (L+R)/2;
* Source code: https://pastebin.com/ChpniVZL for (int i: val[ind]) {
*/ val[2*ind+(A[i] > M)].pb(i);
mapl[ind].pb(sz(val[2*ind])-1);
template<class T, int SZ> struct RMQ { mapr[ind].pb(sz(val[2*ind+1])-1);
T stor[SZ][32-__builtin_clz(SZ)]; }
build(2*ind,L,M);
T comb(T a, T b) { build(2*ind+1,M+1,R);
return min(a,b); }
} }

void build(vector<T>& x) { int getl(int ind, int x) { return x < 0 ? -1 :


F0R(i,sz(x)) stor[i][0] = x[i]; mapl[ind][x]; }
FOR(j,1,32-__builtin_clz(SZ))
F0R(i,SZ-(1<<(j-1))) int getr(int ind, int x) { return x < 0 ? -1 :
stor[i][j] = comb(stor[i][j-1], mapr[ind][x]; }
stor[i+(1<<(j-1))][j-1]);
} int query(int lind, int rind, int k, int ind = 1,
int L = 0, int R = SZ-1) { // how many <= mid
T query(int l, int r) { with index <= r
int x = 31-__builtin_clz(r-l+1); if (L == R) return L;
return comb(stor[l][x],stor[r-(1<<x)+1][x]);
} int M = (L+R)/2;
}; int t = getl(ind,rind)-getl(ind,lind-1);
if (t >= k) return query(getl(ind,lind-1)+1,
getl(ind,rind),k,2*ind,L,M);
6.1.3 Wavelet Tree (6) return query(getr(ind,lind-1)+1,
getr(ind,rind),k-t,2*ind+1,M+1,R);
}
/** };
* Description: Segment tree on values instead of
indices wavelet<1<<17> w;
* Verification: http://www.spoj.com/problems/MKTHNUM/
*/ int main() {
input();
int N,Q, A[100000]; compress();
map<int,int> m; w.build();
6. RANGE QUERIES (2) 9

x1 ++, y1 ++, x2 ++, y2++;


F0R(i,Q) { int b = B.query(x1,x2,y1,y2);
int l,r,k; cin >> l >> r >> k; assert(a == b);
cout << revm[w.query(l-1,r-1,k)] << "\n"; } else break;
} }
} }

6.2 Demos (3) 6.2.3 BBST Demo (4)

6.2.1 Point Update Demo


/**
* Link: http://www.spoj.com/problems/ORDERSET/
/* * Description: Use with treap, splay tree
* Link: http://www.spoj.com/problems/FENTREE/ */
* Description: Use with SegTree, BIT, Sparse SegTree
*/ int main() {
int Q; cin >> Q;
Seg<ll,1<<20> B; F0R(i,Q) {
char c; int d; cin >> c >> d;
int main() { if (c == ’I’) root = ins(root,d);
int N; cin >> N; else if (c == ’D’) root = del(root,d);
FOR(i,1,N+1) { else if (c == ’K’) {
int x; cin >> x; if (!root || root->sz < d) cout
B.upd(i,x); << "invalid\n";
} else cout << find_by_order(d) <<
int q; cin >> q; "\n";
F0R(i,q) { } else cout << order_of_key(d) << "\n";
char c; int a, b; }
cin >> c >> a >> b; }
if (c == ’q’) cout << B.query(a,b) << "\n";
else B.upd(a,b);
}
6.2.4 Range Update Demo (4)
}

/**
* Link: http://www.spoj.com/problems/HORRIBLE/
6.2.2 2D Demo (4)
* Description: Use with range BIT, lazy segtree
*/
/**
* Link: http://www.spoj.com/problems/MATSUM/ (modified) int main() {
* Description: Use with 2D BIT, 2D SegBIT, 2D SegTree int T; cin >> T;
*/ F0R(i,T) {
LazySegTree<ll,1<<17> B =
int main() { LazySegTree<ll,1<<17>();
BIT2D<int,1024> B = BIT2D<int,1024>(); int N, C; cin >> N >> C;
Node<int> S = Node<int>(); F0R(j,C) {
int t; cin >> t;
F0R(i,100000) { if (t == 0) {
int c = rand()&1; int p,q,v; cin >> p >> q >> v;
if (c == 0) { B.upd(p,q,v);
int x = rand() % SZ, y = rand() % SZ, num = } else {
rand() % 100; int p,q; cin >> p >> q;
S.upd(x,y,num); cout << B.qsum(p,q) << "\n";
x++, y++; }
B.upd(x,y,num); }
} else if (c == 1) { }
int x1 = rand() % SZ, y1 = rand() % SZ, x2 }
= rand() % SZ, y2 = rand() % SZ;
if (x1 > x2) swap(x1,x2);
if (y1 > y2) swap(y1,y2);
int a = S.query(x1,x2,y1,y2);
6. RANGE QUERIES (2) 10

6.3 1D Range Queries (3) for (l += SZ, r += SZ; l < r; l >>= 1, r >>=
1) {
6.3.1 Binary Indexed Tree if (l&1) res1 = comb(res1,seg[l++]);
if (r&1) res2 = comb(seg[--r],res2);
/** }
* Description: 1D range sum query with point update return comb(res1,res2);
* Verification: SPOJ Fenwick }
*/ };

template<class T, int SZ> struct BIT {


T bit[SZ+1]; 6.3.3 BIT with Range Update (4)

BIT() { memset(bit,0,sizeof bit); }


/**
void upd(int k, T val) { // add val to index k * Source: GeeksForGeeks?
for( ;k <= SZ; k += (k&-k)) bit[k] += val; * Description: 1D range update, range query
} * Alternative to lazy segment tree
*/
T query(int k) {
T temp = 0; // BIT template
for (;k > 0;k -= (k&-k)) temp += bit[k];
return temp; template<class T, int SZ> struct BITrange {
} BIT<T,SZ> bit[2]; // sums piecewise linear
T query(int l, int r) { return functions
query(r)-query(l-1); } // range query [l,r]
}; void upd(int hi, T val) {
bit[1].upd(1,val), bit[1].upd(hi+1,-val);
bit[0].upd(hi+1,hi*val);
}
6.3.2 SegTree void upd(int lo, int hi, T val) { upd(lo-1,-val),
upd(hi,val); }
/*
* Source: http://codeforces.com/blog/entry/18051 T query(int x) { return
* Description: 1D point update, range query bit[1].query(x)*x+bit[0].query(x); }
* Verification: SPOJ Fenwick T query(int x, int y) { return
*/ query(y)-query(x-1); }
};
template<class T, int SZ> struct Seg {
T seg[2*SZ], MN = 0;
6.3.4 Lazy SegTree (4)
Seg() {
memset(seg,0,sizeof seg);
} /**
* Description: 1D range update, range query
T comb(T a, T b) { return a+b; } // easily change * Verification: SPOJ Horrible
this to min or max */

void upd(int p, T value) { // set value at const ll INF = 1e18; // setting this to MOD can be
position p disastrous :(
for (seg[p += SZ] = value; p > 1; p >>= 1)
seg[p>>1] = comb(seg[(p|1)^1],seg[p|1]); // template<class T, int SZ> struct LazySegTree {
non-commutative operations T sum[2*SZ], mn[2*SZ], lazy[2*SZ]; // set SZ to a
} power of 2

void build() { LazySegTree() {


F0Rd(i,SZ) seg[i] = comb(seg[2*i],seg[2*i+1]); memset (sum,0,sizeof sum);
} memset (mn,0,sizeof mn);
memset (lazy,0,sizeof lazy);
T query(int l, int r) { // sum on interval [l, r] }
T res1 = MN, res2 = MN; r++;
void push(int ind, int L, int R) {
sum[ind] += (R-L+1)*lazy[ind];
6. RANGE QUERIES (2) 11

mn[ind] += lazy[ind]; const int SZ = 1<<20;


if (L != R) lazy[2*ind] += lazy[ind],
lazy[2*ind+1] += lazy[ind]; template<class T> struct node {
lazy[ind] = 0; T val;
} node<T>* c[2];

void pull(int ind) { node() {


sum[ind] = sum[2*ind]+sum[2*ind+1]; val = 0;
mn[ind] = min(mn[2*ind],mn[2*ind+1]); c[0] = c[1] = NULL;
} }

void build() { void upd(int ind, T v, int L = 0, int R = SZ-1) {


F0Rd(i,SZ) pull(i); // add v
} if (L == ind && R == ind) { val += v; return; }

T qsum(int lo, int hi, int ind = 1, int L = 0, int int M = (L+R)/2;
R = SZ-1) { if (ind <= M) {
push(ind,L,R); if (!c[0]) c[0] = new node();
if (lo > R || L > hi) return 0; c[0]->upd(ind,v,L,M);
if (lo <= L && R <= hi) return sum[ind]; } else {
if (!c[1]) c[1] = new node();
int M = (L+R)/2; c[1]->upd(ind,v,M+1,R);
return qsum(lo,hi,2*ind,L,M) + }
qsum(lo,hi,2*ind+1,M+1,R);
} val = 0;
if (c[0]) val += c[0]->val;
T qmin(int lo, int hi, int ind = 1, int L = 0, int if (c[1]) val += c[1]->val;
R = SZ-1) { }
push(ind,L,R);
if (lo > R || L > hi) return INF; T query(int low, int high, int L = 0, int R =
if (lo <= L && R <= hi) return mn[ind]; SZ-1) { // query sum of segment
if (low <= L && R <= high) return val;
int M = (L+R)/2; if (high < L || R < low) return 0;
return min(qmin(lo,hi,2*ind,L,M),
qmin(lo,hi,2*ind+1,M+1,R)); int M = (L+R)/2;
} T t = 0;
if (c[0]) t += c[0]->query(low,high,L,M);
void upd(int lo, int hi, ll inc, int ind = 1, int if (c[1]) t += c[1]->query(low,high,M+1,R);
L = 0, int R = SZ-1) { return t;
push(ind,L,R); }
if (hi < L || R < lo) return;
if (lo <= L && R <= hi) { void UPD(int ind, node* c0, node* c1, int L = 0,
lazy[ind] = inc; int R = SZ-1) { // for 2D segtree
push(ind,L,R); if (L != R) {
return; int M = (L+R)/2;
} if (ind <= M) {
if (!c[0]) c[0] = new node();
int M = (L+R)/2; c[0]->UPD(ind,c0 ? c0->c[0] : NULL,c1 ?
upd(lo,hi,inc,2*ind,L,M); c1->c[0] : NULL,L,M);
upd(lo,hi,inc,2*ind+1,M+1,R); } else {
pull(ind); if (!c[1]) c[1] = new node();
} c[1]->UPD(ind,c0 ? c0->c[1] : NULL,c1 ?
}; c1->c[1] : NULL,M+1,R);
}
}
val = 0;
6.3.5 Sparse SegTree (4)
if (c0) val += c0->val;
if (c1) val += c1->val;
/** }
* Source: Own };
*/
6. RANGE QUERIES (2) 12

6.3.6 SegTree Beats (6) if (R < x || y < L || mx1[ind] <= t) return;


push(ind,L,R);
if (x <= L && R <= y && mx2[ind] < t) {
/**
sum[ind] -= (ll)maxCnt[ind]*(mx1[ind]-t);
* Description: Interval min modifications
mx1[ind] = t;
* Verification:
return;
http://acm.hdu.edu.cn/showproblem.php?pid=5306
}
*/
if (L == R) return;
int M = (L+R)/2;
const int MX = 1<<20;
modify(x,y,t,2*ind,L,M);
modify(x,y,t,2*ind+1,M+1,R);
int N,M, a[MX];
pull(ind);
}
struct Seg {
ll sum[2*MX];
ll qsum(int x, int y, int ind = 1, int L = 0, int
int mx1[2*MX], mx2[2*MX], maxCnt[2*MX];
R = N-1) {
if (R < x || y < L) return 0;
void pull(int ind) {
push(ind,L,R);
mx1[ind] = max(mx1[2*ind],mx1[2*ind+1]);
if (x <= L && R <= y) return sum[ind];
mx2[ind] = max(mx2[2*ind],mx2[2*ind+1]);
maxCnt[ind] = 0;
int M = (L+R)/2;
return
if (mx1[2*ind] == mx1[ind]) maxCnt[ind] +=
qsum(x,y,2*ind,L,M)+qsum(x,y,2*ind+1,M+1,R);
maxCnt[2*ind];
}
else mx2[ind] = max(mx2[ind],mx1[2*ind]);
int qmax(int x, int y, int ind = 1, int L = 0, int
if (mx1[2*ind+1] == mx1[ind]) maxCnt[ind] +=
R = N-1) {
maxCnt[2*ind+1];
if (R < x || y < L) return -1;
else mx2[ind] = max(mx2[ind],mx1[2*ind+1]);
push(ind,L,R);
if (x <= L && R <= y) return mx1[ind];
sum[ind] = sum[2*ind]+sum[2*ind+1];
}
int M = (L+R)/2;
return
void build(int ind = 1, int L = 0, int R = N-1) {
max(qmax(x,y,2*ind,L,M),qmax(x,y,2*ind+1,M+1,R));
if (L == R) {
}
mx1[ind] = sum[ind] = a[L];
};
maxCnt[ind] = 1;
mx2[ind] = -1;
Seg S = Seg();
return;
}
void solve() {
cin >> N >> M;
int M = (L+R)/2;
F0R(i,N) cin >> a[i];
build(2*ind,L,M); build(2*ind+1,M+1,R);
S.build();
pull(ind);
}
F0R(i,M) {
int t; cin >> t;
void push(int ind, int L, int R) {
if (t == 0) {
if (L == R) return;
int x,y,z; cin >> x >> y >> z;
if (mx1[2*ind] > mx1[ind]) {
S.modify(x-1,y-1,z);
sum[2*ind] -=
} else if (t == 1) {
(ll)maxCnt[2*ind]*(mx1[2*ind]-mx1[ind]);
int x,y; cin >> x >> y;
mx1[2*ind] = mx1[ind];
cout << S.qmax(x-1,y-1) << "\n";
}
} else {
if (mx1[2*ind+1] > mx1[ind]) {
int x,y; cin >> x >> y;
sum[2*ind+1] -=
cout << S.qsum(x-1,y-1) << "\n";
(ll)maxCnt[2*ind+1]*(mx1[2*ind+1]-mx1[ind]);
}
mx1[2*ind+1] = mx1[ind];
}
}
}
}

void modify(int x, int y, int t, int ind = 1, int


L = 0, int R = N-1) {
6. RANGE QUERIES (2) 13

6.4 2D Range Queries (4) node<T> seg[SZ+1];

6.4.1 2D BIT SegBit() {


F0R(i,SZ+1) seg[i] = node<T>();
/** }
* Description: Supports point update & range query,
can be extended to range update void upd(int x, int y, int v) { // add v
* Verification: SPOJ matsum for (x++;x <= SZ; x += (x&-x)) seg[x].upd(y,v);
* Dependency: Binary indexed tree }
*/
T query(int x, int y1, int y2) {
template<class T, int SZ> struct BIT2D { T ret = 0;
BIT<T,SZ> bit[SZ+1]; for (;x > 0; x -= (x&-x)) ret +=
void upd(int X, int Y, T val) { seg[x].query(y1,y2);
for (; X <= SZ; X += (X&-X)) bit[X].upd(Y,val); return ret;
} }
T query(int X, int Y) {
T ans = 0; T query(int x1, int x2, int y1, int y2) { // query
for (; X > 0; X -= (X&-X)) ans += sum of rectangle
bit[X].query(Y); return query(x2+1,y1,y2)-query(x1,y1,y2);
return ans; }
} };
T query(int X1, int X2, int Y1, int Y2) {
return query(X2,Y2)-query(X1-1,Y2)
-query(X2,Y1-1)+query(X1-1,Y1-1); 6.4.3 2D SegTree
}
};
/**
int main() { * Source: USACO Mowing the Field
int T; cin >> T; * Dependency: Sparse SegTree
F0R(i,T) { */
int N; cin >> N;
BIT2D<ll,1024> B = BIT2D<ll,1024>(); const int SZ = 1<<17;
while (1) {
string c; cin >> c; template<class T> struct Node {
if (c == "SET") { node<T> seg;
int x, y,num; cin >> x >> y >> num; Node* c[2];
x++, y++;
B.upd(x,y,num-B.query(x,x,y,y)); void upd(int x, int y, T v, int L = 0, int R =
} else if (c == "SUM") { SZ-1) { // add v
int x1, y1, x2, y2; cin >> x1 >> y1 if (L == x && R == x) {
>> x2 >> y2; seg.upd(y,v);
x1 ++, y1 ++, x2 ++, y2++; return;
cout << B.query(x1,x2,y1,y2) << "\n"; }
} else break;
} int M = (L+R)/2;
} if (x <= M) {
} if (!c[0]) c[0] = new Node();
c[0]->upd(x,y,v,L,M);
} else {
if (!c[1]) c[1] = new Node();
6.4.2 2D SegBIT c[1]->upd(x,y,v,M+1,R);
}
/**
* Source: USACO Mowing the Field seg.UPD(y,c[0] ? &c[0]->seg : NULL,c[1] ?
* Dependency: Sparse SegTree &c[1]->seg : NULL);
*/ }

const int SZ = 1<<17; T query(int x1, int x2, int y1, int y2, int L = 0,
int R = SZ-1) { // query sum of rectangle
template<class T> struct SegBit { if (x1 <= L && R <= x2) return
seg.query(y1,y2);
6. RANGE QUERIES (2) 14

if (x2 < L || R < x1) return 0;


tnode (int v) {
int M = (L+R)/2; val = v, sz = 1, pri = rand()+(rand()<<15);
T t = 0; c[0] = c[1] = NULL;
if (c[0]) t += c[0]->query(x1,x2,y1,y2,L,M); }
if (c[1]) t += c[1]->query(x1,x2,y1,y2,M+1,R);
return t; void inOrder(bool f = 0) {
} if (c[0]) c[0]->inOrder();
}; cout << val << " ";
if (c[1]) c[1]->inOrder();
if (f) cout << "\n------------\n";
}
6.4.4 Merge-Sort Tree
void recalc() {
/** sz = 1+(c[0]?c[0]->sz:0)+(c[1]?c[1]->sz:0);
* Description: Similar to 2D segtree, less memory }
* For more complex queries use a customized treap };
* Verification:
http://codeforces.com/contest/785/submission/33953058 pair<tnode*,tnode*> split(tnode* t, int v) { // >= v
*/ goes to the right
if (!t) return {t,t};
template<int SZ> struct mstree {
Tree<pii> val[SZ+1]; // for offline queries use if (v <= t->val) {
vector with binary search instead auto p = split(t->c[0], v);
t->c[0] = p.s; t->recalc();
void upd(int x, int y, int t = 1) { // return {p.f, t};
x-coordinate between 1 and SZ inclusive } else {
for (int X = x; X <= SZ; X += X&-X) { auto p = split(t->c[1], v);
if (t == 1) val[X].insert({y,x}); t->c[1] = p.f; t->recalc();
else val[X].erase({y,x}); return {t, p.s};
} }
} }

int query(int x, int y) { pair<tnode*,tnode*> split_by_order(tnode* t, int v) {


int t = 0; if (!t) return {t,t};
for (;x > 0; x -= x&-x) t += int tmp = t->c[0]?t->c[0]->sz:0;
val[x].order_of_key({y,MOD}); if (v <= tmp) {
return t; auto p = split_by_order(t->c[0], v);
} t->c[0] = p.s; t->recalc();
return {p.f, t};
int query(int lox, int hix, int loy, int hiy) { // } else {
query number of elements within a rectangle auto p = split_by_order(t->c[1], v-tmp-1);
return query(hix,hiy)-query(lox-1,hiy) t->c[1] = p.f; t->recalc();
-query(hix,loy-1)+query(lox-1,loy-1); return {t, p.s};
} }
}; }

tnode* merge(tnode* l, tnode* r) {


if (!l) return r;
6.5 BBST (4) if (!r) return l;
6.5.1 Treap
if (l->pri > r->pri) {
l->c[1] = merge(l->c[1],r);
/* l->recalc();
* Sources: various return l;
* Description: Easiest BBST } else {
* Verification: http://www.spoj.com/problems/ORDERSET/ r->c[0] = merge(l,r->c[0]);
*/ r->recalc();
return r;
struct tnode { }
int val, pri, sz; }
tnode *c[2];
6. RANGE QUERIES (2) 15

tnode* ins(tnode* x, int v) { // insert value v sum[x] = sum[y];


auto a = split(x,v); sum[y] = sum[c[y][0]]+sum[c[y][1]]+1;
auto b = split(a.s,v+1); pp[x] = pp[y]; pp[y] = 0;
return merge(a.f,merge(new tnode(v),b.s)); }
}
void splay(int x) {
tnode* del(tnode* x, int v) { // delete all values while (p[x]) {
equal to v int y = p[x], z = p[y];
auto a = split(x,v), b = split(a.s,v+1); int dy = getDir(y,x), dz = getDir(z,y);
return merge(a.f,b.s); if (!z) rotate(y,dy);
} else if (dy == dz) rotate(z,dz),
rotate(y,dy);
tnode *root; else rotate(y,dy), rotate(z,dz);
}
int order_of_key(int x) { }
auto a = split(root,x);
int t = a.f?a.f->sz:0; void dis(int v, int d) {
root = merge(a.f,a.s); p[c[v][d]] = 0, pp[c[v][d]] = v;
return t; sum[v] -= sum[c[v][d]];
} c[v][d] = 0;
}
int find_by_order(int x) {
auto a = split_by_order(root,x); void con(int v, int d) {
auto b = split_by_order(a.f,x-1); c[pp[v]][d] = v;
int t = b.s->val; sum[pp[v]] += sum[v];
root = merge(merge(b.f,b.s),a.s); p[v] = pp[v], pp[v] = 0;
return t; }
}
void access(int v) {
// v is brought to the root of auxiliary tree
// modify preferred paths
6.5.2 Link-Cut Tree (5)
splay(v);
/** dis(v,1);
* Source: Dhruv Rohatgi
* Usage: USACO Camp - The Applicant while (pp[v]) {
*/ int w = pp[v]; splay(w);
dis(w,1), con(v,1);
template<int SZ> struct LCT { splay(v);
int p[SZ], pp[SZ], c[SZ][2], sum[SZ]; }
}
LCT () {
FOR(i,1,SZ) sum[i] = 1; int find_root(int v) {
memset(p,0,sizeof p); access(v);
memset(pp,0,sizeof pp); while (c[v][0]) v = c[v][0];
memset(c,0,sizeof c); access(v);
} return v;
}
int getDir(int x, int y) {
return c[x][0] == y ? 0 : 1; int find_depth(int v) {
} access(v);
return sum[c[v][0]];
void setLink(int x, int y, int d) { }
c[x][d] = y, p[y] = x;
} void cut(int v) {
// cut link between v and par[v]
void rotate(int y, int d) { access(v);
int x = c[y][d], z = p[y]; pp[c[v][0]] = p[c[v][0]] = 0; // fix
setLink(y,c[x][d^1],d); sum[v] -= sum[c[v][0]];
setLink(x,y,d^1); c[v][0] = 0;
setLink(z,x,getDir(z,y)); }
6. RANGE QUERIES (2) 16

void link(int v, int w) { if (c[1]) c[1]->inOrder();


// v, which is root of another tree, is now if (f) cout << "\n------------\n";
child of w }
access(v), access(w);
pp[w] = v; con(w,0); void recalc() {
} sz = 1+(c[0]?c[0]->sz:0)+(c[1]?c[1]->sz:0);
}
int anc(int v, int num) { };
if (find_depth(v) < num) return 0;
access(v); void setLink(snode* x, snode* y, int d) {
v = c[v][0]; if (x) x->c[d] = y, x->recalc();
if (y) y->p = x;
while (1) { }
if (sum[c[v][1]] >= num) v = c[v][1];
else if (sum[c[v][1]]+1 == num) return v; snode* unLink(snode* x, int d) {
else num -= (sum[c[v][1]]+1), v = c[v][0]; snode* y = x->c[d];
} x->c[d] = NULL; x->recalc();
} if (y) y->p = NULL;
return y;
void print(int x) { }
FOR(i,1,x+1) cout << i << " " << find_root(i)
<< " " << find_depth(i) << " " << anc(i,2) int getDir(snode* x, snode* y) {
<< "\n"; if (!x) return -1;
cout << "\n"; return x->c[0] == y ? 0 : 1;
} }
};
void rot(snode* x, int d) {
LCT<100001> L; snode *y = x->c[d], *z = x->p;
setLink(x, y->c[d^1], d);
int main() { setLink(y, x, d^1);
L.link(2,1); L.link(3,1); L.link(4,1); L.link(5,4); setLink(z, y, getDir(z, x));
L.link(10,4); L.link(7,6); L.link(8,7); }
L.link(9,8);
L.print(10); snode* splay(snode* x) {
while (x && x->p) {
L.cut(4); L.link(4,8); snode* y = x->p, *z = y->p;
L.print(10); int dy = getDir(y, x), dz = getDir(z, y);
} if (!z) rot(y, dy);
else if (dy == dz) rot(z, dz), rot(y, dy);
else rot(y, dy), rot(z, dz);
}
6.5.3 Splay Tree (5)
return x;
}
/*
* Description: Based off treap code snode* find(snode *cur, int v) {
* Source: if (!cur) return cur;
https://sites.google.com/site/kc97ble/container/splay-tree/splaytree-cpp-3
snode* x;
* Verification: http://www.spoj.com/problems/ORDERSET/ if (cur->val >= v) x = find(cur->c[0],v);
*/ else x = find(cur->c[1],v);
return x?x:cur;
struct snode { }
int val, sz;
snode *p, *c[2]; snode* getmx(snode* x) {
return x->c[1]?getmx(x->c[1]):x;
snode (int v) { }
val = v, sz = 1;
c[0] = c[1] = p = NULL; pair<snode*,snode*> split(snode* x, int v) {
} if (!x) return {x,x};
snode* y = find(x,v); y = splay(y);
void inOrder(bool f = 0) { if (y->val >= v) return {unLink(y,0),y};
if (c[0]) c[0]->inOrder(); else return {y,unLink(y,1)};
cout << val << " "; }
6. RANGE QUERIES (2) 17

* Description: persistent segtree node without lazy


snode* find_by_order(snode* x, int v) { updates
int tmp = x->c[0]?x->c[0]->sz:0; * Verification: Codeforces Problem 893F - Subtree
if (v < tmp) return find_by_order(x->c[0],v); Minimum Query
else if (v == tmp) return x; * Implementation:
else return find_by_order(x->c[1],v-tmp-1); http://codeforces.com/contest/893/submission/32652140
} */

pair<snode*,snode*> split_by_order(snode* x, int v) { struct Node {


// left subtree has v elements int val = 0;
if (!x) return {x,x}; Node* c[2];
if (v == x->sz) return {x,NULL};
snode* y = find_by_order(x,v); y = splay(y); Node* copy() {
return {unLink(y,0),y}; Node* x = new Node(); *x = *this;
} return x;
}
snode* merge(snode* x, snode* y) {
if (!x) return y; int query(int low, int high, int L, int R) {
x = splay(getmx(x)); if (low <= L && R <= high) return val;
setLink(x,y,1); if (R < low || high < L) return MOD;
return x; int M = (L+R)/2;
} return min(c[0]->query(low,high,L,M),
c[1]->query(low,high,M+1,R));
// same as treap }

snode* ins(snode* x, int v) { // insert value v Node* upd(int ind, int v, int L, int R) {
auto a = split(x,v); if (R < ind || ind < L) return this;
auto b = split(a.s,v+1); Node* x = copy();
return merge(a.f,merge(new snode(v),b.s));
} if (ind <= L && R <= ind) {
x->val += v;
snode* del(snode* x, int v) { // delete all values return x;
equal to v }
auto a = split(x,v), b = split(a.s,v+1);
return merge(a.f,b.s); int M = (L+R)/2;
} x->c[0] = x->c[0]->upd(ind,v,L,M);
x->c[1] = x->c[1]->upd(ind,v,M+1,R);
snode* root; x->val = min(x->c[0]->val,x->c[1]->val);

int order_of_key(int x) { return x;


auto a = split(root,x); }
int t = a.f?a.f->sz:0;
root = merge(a.f,a.s); void build(vi& arr, int L, int R) {
return t; if (L == R) {
} if (L < (int)arr.size()) val = arr[L];
else val = 0;
int find_by_order(int x) { return;
auto a = split_by_order(root,x); }
auto b = split_by_order(a.f,x-1); int M = (L+R)/2;
int t = b.s->val; c[0] = new Node();
root = merge(merge(b.f,b.s),a.s); c[0]->build(arr,L,M);
return t; c[1] = new Node();
} c[1]->build(arr,M+1,R);
val = min(c[0]->val,c[1]->val);
}
};
6.6 Persistent Queries (5)
template<int SZ> struct pers {
6.6.1 Basic Persistent SegTree
Node* loc[SZ+1]; // stores location of root after
ith update
/** int nex = 1;
6. RANGE QUERIES (2) 18

pers() { loc[0] = new Node(); } x->val = min(x->c[0]->val,x->c[1]->val);

void upd(int ind, int val) { return x;


loc[nex] = loc[nex-1]->upd(ind,val,0,SZ-1); }
nex++;
} void build(vi& arr, int L, int R) {
void build(vi& arr) { if (L == R) {
loc[0]->build(arr,0,SZ-1); if (L < sz(arr)) val = arr[L];
} else val = 0;
int query(int ti, int low, int high) { return;
return loc[ti]->query(low,high,0,SZ-1); }
} int M = (L+R)/2;
}; c[0] = new node();
c[0]->build(arr,L,M);
c[1] = new node();
c[1]->build(arr,M+1,R);
6.6.2 Lazy Persistent SegTree
val = min(c[0]->val,c[1]->val);
}
/** };
* Source:
http://codeforces.com/blog/entry/47108?#comment-315047 template<int SZ> struct pers {
* Description: Node + lazy updates node* loc[SZ+1]; // stores location of root after
*/ ith update
int nex = 1;
struct node {
int val = 0, lazy = 0; pers() { loc[0] = new node(); }
node* c[2];
void upd(int low, int high, int val) {
node* copy() { loc[nex] =
node* x = new node(); *x = *this; loc[nex-1]->upd(low,high,val,0,SZ-1);
return x; nex++;
} }
void build(vi& arr) {
void push() { loc[0]->build(arr,0,SZ-1);
if (!lazy) return; }
F0R(i,2) if (c[i]) { int query(int ti, int low, int high) {
c[i] = new node(*c[i]); return loc[ti]->query(low,high,0,SZ-1);
c[i]->lazy += lazy; }
} };
lazy = 0;
} pers<8> p;

int query(int low, int high, int L, int R) { int main() {


if (low <= L && R <= high) return val; vi arr = {1,7,2,3,5,9,4,6};
if (R < low || high < L) return MOD; p.build(arr);
int M = (L+R)/2;
return lazy+min(c[0]->query(low,high,L,M), p.upd(1,2,2); // 1 9 4 3 5 9 4 6
c[1]->query(low,high,M+1,R));
} F0R(i,8) {
FOR(j,i,8) cout << p.query(1,i,j) << " ";
node* upd(int low, int high, int v, int L, int R) { cout << "\n";
if (R < low || high < L) return this; }
node* x = copy(); cout << "\n";
if (low <= L && R <= high) {
x->lazy += v, x->val += v; p.upd(4,7,5); // 1 9 4 3 10 14 9 11
return x; F0R(i,8) {
} FOR(j,i,8) cout << p.query(2,i,j) << " ";
push(); cout << "\n";
}
int M = (L+R)/2; cout << "\n";
x->c[0] = x->c[0]->upd(low,high,v,L,M);
x->c[1] = x->c[1]->upd(low,high,v,M+1,R); F0R(i,8) {
7. DP (3) 19

FOR(j,i,8) cout << p.query(1,i,j) << " "; 7 DP (3)


cout << "\n";
}
cout << "\n"; 7.1 Examples
}
7.1.1 Knapsack

// https://open.kattis.com/problems/knapsack
6.6.3 Low-Memory Persistent Segment Tree
double C;
//uses about 34 MB int n,v[2000],w[2000],dp[2001][2001];
const int MAXN = 100100;
int N = 100000; void solve() {
struct Node { F0R(i,n) cin >> v[i] >> w[i];
ll val; F0R(i,n) {
} SEG[20*MAXN]; F0R(j,C+1) dp[i+1][j] = dp[i][j];
int e = 0; F0R(j,C+1) if (w[i]+j <= C) dp[i+1][w[i]+j] =
int LFT[20*MAXN], RGT[20*MAXN]; max(dp[i+1][w[i]+j],dp[i][j]+v[i]);
}
int roots[MAXN];
vi ans;
int build(int l = 0, int r = N - 1) { int x = C;
//build from L to R inclusive. F0Rd(i,n) if (dp[i][x] != dp[i+1][x]) x -= w[i],
int x = ++e; ans.pb(i);
if (l == r){
SEG[x].val = 0; cout << ans.size() << "\n";
LFT[x] = -1; for (int i: ans) cout << i << " ";
RGT[x] = -1; cout << "\n";
return x; }
}
int mid = (l + r)/2;
LFT[x] = build(l, mid);
7.1.2 Longest Common Subsequence
RGT[x] = build(mid + 1, r);
return x;
} /**
* Description: Classic DP example
int upd(int cur, int pos, int set, int l = 0, int r = */
N - 1) {
//set a[pos] = set in the root cur int dp[1001][1001];
if (r < pos || pos < l) return cur; string a,b;
int x = ++e;
//we’re creating a new node int main() {
if (l == r){ cin >> a >> b;
SEG[x].val = set; F0R(i,sz(a)) F0R(j,b.sz(b)) {
return x; dp[i+1][j+1] = max(dp[i+1][j],dp[i][j+1]);
} if (a[i] == b[j]) dp[i+1][j+1] =
int m = (l+r)/2; max(dp[i+1][j+1],dp[i][j]+1);
LFT[x] = upd(LFT[cur], pos, set, l, m); }
RGT[x] = upd(RGT[cur], pos, set, m + 1, r); cout << dp[sz(a)][sz(b)];
SEG[x].val = SEG[LFT[x]].val + SEG[RGT[x]].val; }
return x;
}
7.1.3 Longest Increasing Subsequence
ll query(int cur, int L, int R, int l = 0, int r = N -
1){
if (r < L || R < l) return 0LL; /**
int m = (l + r)/2; * Description: DP with Binary Search
if (L <= l && r <= R) return SEG[cur].val; */
return query(LFT[cur], L, R, l, m) +
query(RGT[cur], L, R, m + 1, r); vi bes = {0};
} int n;
8. STRINGS (3) 20

void ad(int x) { int ans = MOD;


int lo = 0, hi = sz(bes)-1; FOR(j,1,N) ans =
while (lo < hi) { min(ans,dp[j][(1<<N)-1]+dist[j][0]);
int mid = (lo+hi+1)/2; return ans;
if (bes[mid] < x) lo = mid; }
else hi = mid-1;
} int main() {
if (lo == sz(bes)-1) bes.pb(0); int T; cin >> T;
bes[lo+1] = x; F0R(i,T) {
} cin >> N; N++;
F0R(j,N) F0R(k,N) if (j != k) cin >>
int main() { dist[j][k];
cin >> n; cout << solve() << "\n";
F0R(i,n) { }
int x; cin >> x; }
ad(x);
}
cout << sz(bes)-1;
} 7.2 Divide And Conquer (4)

/**
7.1.4 String Removals * Source: Own
* Usage: CEOI 2004 Two Sawmills
*/
/**
* Description: DP eliminates overcounting void divi(int lo, int hi, int L, int R) {
* Verification: https://cses.fi/problemset/task/1149/ if (lo > hi) return;
*/
int mid = (lo+hi)/2;
int distinct(string S) { pair<ll,int> tmp = {1e18,-1};
vi tot(26); FOR(i,max(mid+1,L),R+1)
int ans = 1; tmp = min(tmp,{calc(0,mid)+calc(mid+1,i)
for (char c: S) { +calc(i+1,n),i});
int t = (ans-tot[c-’a’]+MOD)%MOD; ans = min(ans,tmp.f);
tot[c-’a’] = (tot[c-’a’]+t)%MOD;
ans = (ans+t)%MOD; divi(lo,mid-1,L,tmp.s);
} divi(mid+1,hi,tmp.s,R);
return ans; }
}

7.1.5 Traveling Salesman (4) 8 Strings (3)

/** 8.1 Hashing


* Description: Bitset DP example
* Solves TSP for small N /**
*/ * Source: own
* Description: Pairs reduce frequency of collision
const int MX = 15; * Verification: Dec 17 Plat 1
*/
int N, dp[MX][1<<MX], dist[MX][MX];
typedef pair<ll, ll> pll;
int solve() {
F0R(i,N) F0R(j,1<<N) dp[i][j] = MOD; template<class T> pair<T,T> operator+(const pair<T,T>&
l, const pair<T,T>& r) {
dp[0][1] = 0; return {(l.f+r.f)%MOD,(l.s+r.s)%MOD};
F0R(j,1<<N) F0R(i,N) if (j&(1<<i)) }
F0R(k,N) if (!(j&(1<<k)))
dp[k][j^(1<<k)] = min(dp[k][j^(1<<k)], template<class T> pair<T,T> operator-(const pair<T,T>&
dp[i][j]+dist[i][k]); l, const pair<T,T>& r) {
return {(l.f-r.f+MOD)%MOD,(l.s-r.s+MOD)%MOD};
8. STRINGS (3) 21

} cout << lcp(h,H);


}
template<class T> pair<T,T> operator*(const pair<T,T>&
l, const T& r) {
return {l.f*r%MOD,l.s*r%MOD};
} 8.2 Bitset Trie (4)

template<class T> pair<T,T> operator*(const pair<T,T>& /**


l, const pair<T,T>& r) { * Source: Algorithms Gym
return {l.f*r.f%MOD,l.s*r.s%MOD}; * Verification: January Easy 2018 - Shubham and
} Subarray Xor
*/
struct hsh {
string S; template<int MX> struct tri {
vector<pll> po, ipo, cum; int nex = 0, ans = 0;
pll base = mp(948392576,573928192); int trie[MX][2]; // easily changed to character

ll modpow(ll b, ll p) { tri() {
return !p?1:modpow(b*b%MOD,p/2)*(p&1?b:1)%MOD; memset(trie,0,sizeof trie);
} }

ll inv(ll x) { void ins(int x) {


return modpow(x,MOD-2); int cur = 0;
} F0Rd(i,30) {
int t = (x&(1<<i))>>i;
void gen(string _S) { if (!trie[cur][t]) trie[cur][t] = ++nex;
S = _S; cur = trie[cur][t];
po.resize(sz(S)), ipo.resize(sz(S)), }
cum.resize(sz(S)+1); }
po[0] = ipo[0] = {1,1};
FOR(i,1,sz(S)) { void test(int x) {
po[i] = po[i-1]*base; int cur = 0;
ipo[i] = {inv(po[i].f),inv(po[i].s)}; F0Rd(i,30) {
} int t = ((x&(1<<i))>>i) ^ 1;
F0R(i,sz(S)) cum[i+1] = if (!trie[cur][t]) t ^= 1;
cum[i]+po[i]*(ll)(S[i]-’a’+1); cur = trie[cur][t];
} if (t) x ^= (1<<i);
}
pll get(int l, int r) { ans = max(ans,x);
return ipo[l]*(cum[r+1]-cum[l]); }
} };
};

int lcp(hsh& a, hsh& b) { // can be used to generate a


suffix array 8.3 Suffix Array (4)
int lo = 0, hi = min(sz(a.S),sz(b.S));
8.3.1 Suffix Array
while (lo < hi) {
int mid = (lo+hi+1)/2;
if (a.get(0,mid-1) == b.get(0,mid-1)) lo = mid; /**
else hi = mid-1; * Source: SuprDewd CP Course
} * Task: https://open.kattis.com/problems/suffixsorting
return lo; * KACTL version is slightly faster
} * Verification: USACO December 2017: Standing out from
the herd:
int main() { http://usaco.org/index.php?page=viewproblem2&cpid=768
string _S = "abacaba"; * Code to Verify: https://pastebin.com/y2Z9FYr6
hsh h; h.gen(_S); */
F0R(i,sz(_S)) FOR(j,i,sz(_S)) cout << i << " " <<
j << " " << h.get(i,j).f << " " << struct suffix_array {
h.get(i,j).s << "\n"; int N;
vector<vi> P;
hsh H; H.gen("abadaba"); vector<array<int,3>> L;
8. STRINGS (3) 22

vi idx; 8.3.2 Reverse Burrows-Wheeler (6)


string str;
/**
/*void bucket(int ind) {
* Verification: https://cses.fi/problemset/task/1113/
int mn = MOD, mx = -MOD;
*/
for (auto a: L) mn = min(mn,a[ind]), mx =
string transform(string s) {
max(mx,a[ind]);
vector<pair<char,int>> v;
vector<array<int,3>> tmp[mx-mn+1];
int nex[sz(s)];
F0Rd(i,sz(L)) tmp[L[i][ind]-mn].pb(L[i]);
F0R(i,sz(s)) v.pb({s[i],i});
int nex = 0;
sort(all(v));
F0R(i,mx-mn+1) for (auto a: tmp[i]) L[nex++] =
F0R(i,sz(v)) nex[i] = v[i].s;
a;
}
int cur = nex[0];
string ret;
void bucket_sort() {
while (cur != 0) {
bucket(1), bucket(0);
ret += v[cur].f;
}*/
cur = nex[cur];
}
suffix_array(string _str) {
return ret;
str = _str; N = sz(str);
}
P.pb(vi(N)); L.resize(N);
F0R(i,N) P[0][i] = str[i];

for (int stp = 1, cnt = 1; cnt < N; stp ++, 8.4 Z (5)
cnt *= 2) {
P.pb(vi(N)); 8.4.1 Aho-Corasick
F0R(i,N) L[i] = {P[stp-1][i],i+cnt < N ?
P[stp-1][i+cnt] : -1,i}; /**
sort(all(L)); * Source: https://ideone.com/0cMjZJ
// bucket_sort(); * Usage: Kattis stringmultimatching
F0R(i,N) { */
if (i && mp(L[i][0],L[i][1]) ==
mp(L[i-1][0],L[i-1][1])) template<int SZ> struct Aho {
P[stp][L[i][2]] = P[stp][L[i-1][2]]; int link[SZ], dict[SZ], sz = 1, num = 0;
else P[stp][L[i][2]] = i; vector<pii> ind[SZ];
} map<char,int> to[SZ];
} vi oc[SZ];
queue<int> q;
idx.resize(N);
F0R(i,sz(P.back())) idx[P.back()[i]] = i; Aho() {
} memset(link,0,sizeof link);
memset(dict,0,sizeof dict);
int lcp(int x, int y) { }
int res = 0;
if (x == y) return N-x; void add(string s) {
for (int k = sz(P) - 1; k >= 0 && x < N && y < int v = 0;
N; k--) { for(auto c: s) {
if (P[k][x] == P[k][y]) { if (!to[v].count(c)) to[v][c] = sz++;
x += 1 << k; v = to[v][c];
y += 1 << k; }
res += 1 << k; dict[v] = v; ind[v].pb({++num,sz(s)});
} }
}
return res; void push_links() {
} link[0] = -1; q.push(0);
}; while (sz(q)) {
int v = q.front(); q.pop();
for (auto it: to[v]) {
8. STRINGS (3) 23

char c = it.f; int u = it.s, j = * Description: Calculates length of largest palindrome


link[v]; centered at each character of string
while (j != -1 && !to[j].count(c)) j = * Verification: http://www.spoj.com/problems/MSUBSTR/
link[j]; */
if (j != -1) {
link[u] = to[j][c]; vi manacher(string s) {
if (!dict[u]) dict[u] = string s1 = "@";
dict[link[u]]; for (char c: s) s1 += c, s1 += "#";
} s1[s1.length()-1] = ’&’;
q.push(u);
} vi ans(s1.length()-1);
} int lo = 0, hi = 0;
} FOR(i,1,s1.length()-1) {
ans[i] = min(hi-i,ans[hi-i+lo]);
void process(int pos, int cur) { while (s1[i-ans[i]-1] == s1[i+ans[i]+1])
cur = dict[cur]; ans[i] ++;
while (cur) { if (i+ans[i] > hi) lo = i-ans[i], hi =
for (auto a: ind[cur]) i+ans[i];
oc[a.f].pb(pos-a.s+1); }
cur = dict[link[cur]];
} ans.erase(ans.begin());
} F0R(i,sz(ans)) if ((i&1) == (ans[i]&1)) ans[i] ++;
// adjust lengths
int nex(int pos, int cur, char c) { return ans;
while (cur != -1 && !to[cur].count(c)) cur = }
link[cur];
if (cur == -1) cur = 0; int main() {
else cur = to[cur][c]; int T; cin >> T;
process(pos, cur); F0R(i,T) {
return cur; pii bes = {0,0};
} string s; cin >> s;
}; vi t = manacher(s);
for (int i: t) {
Aho<100001> A; if (i > bes.f) bes = {i,1};
else if (i == bes.f) bes.s++;
int n; }
cout << bes.f << " " << bes.s << "\n";
void solve() { }
A = Aho<100001>(); }
cin >> n;
F0R(i,n) {
string pat; getline(cin,pat); if (!i)
8.4.3 Minimum Rotation
getline(cin,pat);
A.add(pat);
} /**
A.push_links(); * Source: KACTL
* Unused
string t; getline(cin,t); */
int cur = 0;
F0R(i,sz(t)) cur = A.nex(i,cur,t[i]); int min_rotation(string s) {
FOR(i,1,n+1) { int a=0, N=sz(s); s += s;
for (int j: A.oc[i]) cout << j << " "; F0R(b,N) F0R(i,N) {
cout << "\n"; if (a+i == b || s[a+i] < s[b+i]) {b +=
} max(0, i-1); break;}
} if (s[a+i] > s[b+i]) { a = b; break; }
}
return a;
}
8.4.2 Manacher

/**
* Source: http://codeforces.com/blog/entry/12143
9. TREES (4) 24

8.4.4 Z void dfs(int cur) {


memset(dist,0,sizeof dist);
dfs(cur,-1);
/**
}
* Source: http://codeforces.com/blog/entry/3107
* Description: similar to KMP
int treeDiameter() {
* Verification: POI 12 Template
dfs(1);
*/
int bes = 0; FOR(i,1,n+1) if (dist[i] > dist[bes])
bes = i;
vi z(string s) {
dfs(bes); FOR(i,1,n+1) if (dist[i] > dist[bes])
int N = s.length(); s += ’#’;
bes = i;
vi ans(N); ans[0] = N;
return dist[bes];
while (s[1+ans[1]] == s[ans[1]]) ans[1] ++;
}
int L = 1, R = ans[1];
int main() {
FOR(i,2,N) {
cin >> n;
if (i <= R) ans[i] = min(R-i+1,ans[i-L]);
F0R(i,n-1) {
while (s[i+ans[i]] == s[ans[i]]) ans[i] ++;
int a, b; cin >> a >> b;
if (i+ans[i]-1 > R) L = i, R = i+ans[i]-1;
adj[a].pb(b), adj[b].pb(a);
}
}
return ans;
cout << treeDiameter();
}
}
vi get(string a, string b) { // find prefixes of a in b
string s = a+"@"+b;
vi t = z(s); 9.2 Queries
return vi(t.begin()+a.length()+1,t.end());
} 9.2.1 Heavy-Light Set

int main() {
/**
vi x = z("abcababcabcaba");
* Description: offline subtree queries in O(Nlog^2N)
for (int i: x) cout << i << " ";
* Verification: January Easy 2018 - Shubham & Tree 1
cout << "\n";
*/
x = get("abcab","uwetrabcerabcab");
const int MX = 200001;
for (int i: x) cout << i << " ";
}
struct HeavyLightSet {
int loc[MX], sub[MX], par[MX], val[MX];
vi child[MX];
map<int,int> dat[MX];
9 Trees (4)
void comb(int a, int b) {
9.1 Tree Diameter int A = loc[a], B = loc[b];
if (sz(dat[A]) < sz(dat[B])) swap(a,b),
swap(A,B);
/**
for (auto& x: dat[B]) dat[A][x.f] += x.s;
* Might not be obvious why this works!
dat[B].clear(); loc[b] = A;
* Verification: http://www.spoj.com/problems/PT07Z/
}
*/
void process(int ind) {
const int MX = 10001;
sub[ind] = 1; loc[ind] = ind;
dat[ind][val[ind]] ++;
int n, dist[MX];
for (int i: child[ind]) {
vi adj[MX];
process(i);
comb(i,ind);
void dfs(int cur, int pre) {
sub[ind] += sub[i];
for (int i: adj[cur]) if (i != pre) {
}
dist[i] = dist[cur]+1;
// now do stuff with values
dfs(i,cur);
}
}
};
}
9. TREES (4) 25

9.2.2 LCA Demo F0Rd(k,MAXK) if (depth[u] >= depth[v]+(1<<k))


u = parK[k][u];
F0Rd(k,MAXK) if (parK[k][u] != parK[k][v]) u =
/**
parK[k][u], v = parK[k][v];
* Debug the Bugs
* Description: Use for both LCA’s
if(u != v) u = parK[0][u], v = parK[0][v];
*/
return u;
}
LCA L;
int dist(int u, int v) {
int Q;
return depth[u]+depth[v]-2*depth[lca(u,v)];
}
int main() {
};
cin >> L.V >> Q >> L.R;
F0R(i,L.V-1) {
int u,v; cin >> u >> v;
L.addEdge(u,v); 9.2.4 LCA with RMQ
}
L.construct();
/**
* Description: Euler Tour LCA w/ O(1) query
F0R(i,Q) {
* Source: own
int u,v; cin >> u >> v;
* Verification: Debug the Bugs
cout << L.lca(u,v) << "\n";
* Dependency: Range Minimum Query
}
*/
}
const int MAXN = 100001;

9.2.3 LCA with Binary Jumps struct LCA {


vi edges[MAXN];
RMQ<pii,2*MAXN> r;
/**
vector<pii> tmp;
* Source: USACO Camp
int depth[MAXN], pos[MAXN];
* Verification: Debug the Bugs
*/
int V, R;
const int MAXN = 100001, MAXK = 17;
void addEdge(int u, int v) {
edges[u].pb(v), edges[v].pb(u);
struct LCA {
}
int V, R;
vi edges[MAXN];
void dfs(int u, int prev){
int parK[MAXK][MAXN];
pos[u] = sz(tmp); depth[u] = depth[prev]+1;
int depth[MAXN];
tmp.pb({depth[u],u});
for (int v: edges[u]) if (v != prev) {
void addEdge(int u, int v) {
dfs(v, u);
edges[u].pb(v), edges[v].pb(u);
tmp.pb({depth[u],u});
}
}
}
void dfs(int u, int prev){
parK[0][u] = prev;
void construct() {
depth[u] = depth[prev]+1;
dfs(R, 0);
for (int v: edges[u]) if (v != prev) dfs(v, u);
r.build(tmp);
}
}
void construct() {
int lca(int u, int v){
dfs(R, 0);
u = pos[u], v = pos[v];
FOR(k,1,MAXK) FOR(i,1,V+1)
if (u > v) swap(u,v);
parK[k][i] = parK[k-1][parK[k-1][i]];
return r.query(u,v).s;
}
}
int lca(int u, int v){
int dist(int u, int v) {
if (depth[u] < depth[v]) swap(u,v);
return depth[u]+depth[v]-2*depth[lca(u,v)];
}
9. TREES (4) 26

}; 9.3.2 Heavy-Light Decomposition

/**
9.3 Advanced * Source: http://codeforces.com/blog/entry/22072
* Dependency: Lazy SegTree
9.3.1 Centroid Decomposition * Verification: USACO Grass Planting
*/
/**
vector<vi> graph;
* Source: own
* Verification Problem: Ciel and Commander
template <int V> struct HeavyLight { // sum queries,
(http://codeforces.com/contest/321/problem/C)
sum updates
* Code:
int parent[V], heavy[V], depth[V];
http://codeforces.com/contest/321/submission/33952270
int root[V], treePos[V];
*/
LazySegTree<V> tree;
const int MX = 100001;
void init() {
int n = graph.size();
int N, visit[MX], sub[MX], par[MX];
FOR(i,1,n+1) heavy[i] = -1;
vi adj[MX];
parent[1] = -1, depth[1] = 0;
dfs(1);
void dfs (int no) {
for (int i = 1, currentPos = 0; i <= n; ++i)
sub[no] = 1;
if (parent[i] == -1 || heavy[parent[i]]
for (int i: adj[no]) if (!visit[i] && i !=
!= i)
par[no]) {
for (int j = i; j != -1; j =
par[i] = no;
heavy[j]) {
dfs(i);
root[j] = i;
sub[no] += sub[i];
treePos[j] = currentPos++;
}
}
}
}
int get_centroid(int x) {
int dfs(int v) {
par[x] = 0;
int size = 1, maxSubtree = 0;
dfs(x);
for (auto u : graph[v]) if (u != parent[v]) {
int sz = sub[x];
parent[u] = v;
while (1) {
depth[u] = depth[v] + 1;
pii mx = {0,0};
int subtree = dfs(u);
for (int i: adj[x]) if (!visit[i] && i !=
if (subtree > maxSubtree) heavy[v] = u,
par[x]) mx = max(mx,{sub[i],i});
maxSubtree = subtree;
if (mx.f*2 > sz) x = mx.s;
size += subtree;
else return x;
}
}
return size;
}
}
void solve (int x) {
template <class BinaryOperation>
x = get_centroid(x); visit[x] = 1;
void processPath(int u, int v, BinaryOperation op)
// do stuff
{
cout << x << "\n";
for (; root[u] != root[v]; v =
for (int i: adj[x]) if (!visit[i]) solve(i);
parent[root[v]]) {
}
if (depth[root[u]] > depth[root[v]])
swap(u, v);
int main() {
op(treePos[root[v]], treePos[v]);
cin >> N;
}
F0R(i,N-1) {
if (depth[u] > depth[v]) swap(u, v);
int a,b; cin >> a >> b;
op(treePos[u]+1, treePos[v]); // assumes
adj[a].pb(b), adj[b].pb(a);
values are stored in edges, not vertices
}
}
solve(1);
}
void modifyPath(int u, int v, int value) {
processPath(u, v, [this, &value](int l, int r)
{ tree.upd(l, r, value); });
10. MATH (4) 27

} * Observation: number of operations needed s.t.


* phi(phi(...phi(n)...))=1
ll queryPath(int u, int v) { * is O(log n).
ll res = 0; * Euler’s theorem: a^{\phi(p)}\equiv 1 (mod p),
processPath(u, v, [this, &res](int l, int r) { gcd(a,p)=1
res += tree.qsum(l, r); }); * Verification: CF Power Tower
return res; */
}
}; int phi(int x) {
if (x == 1) return 1;
HeavyLight<1<<17> H; int X = x;
int N,M;
vi pri;
int main() { for (int i = 2; i*i <= x; ++i) if (x % i == 0) {
cin >> N >> M; while (x % i == 0) x /= i;
graph.resize(N+1); pri.pb(i);
F0R(i,N-1) { }
int a,b; cin >> a >> b;
graph[a].pb(b), graph[b].pb(a); if (x > 1) pri.pb(x);
} for (int i: pri) { X /= i; X *= i-1; }
H.init(); return X;
F0R(i,M) { }
char c; int A,B;
cin >> c >> A >> B;
if (c == ’P’) H.modifyPath(A,B,1);
10.1.3 CRT (5)
else cout << H.queryPath(A,B) << "\n";
}
} /**
* Source: Own
* Verification:
* Kattis generalchineseremainder
10 Math (4) * POI 9 Rhyme
*/
10.1 Number Theory typedef pair<ll,ll> pll;
10.1.1 Eratosthenes’ Sieve
struct CRT {
ll n,m,a,b;
/** map<ll,pii> M;
* Source: KACTL? bool bad;
* https://open.kattis.com/problems/primesieve
*/ ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1
a %= b;
template<int SZ> struct Sieve { if (a <= 1) return a;
bitset<SZ+1> comp; ll i = inv(b%a,a);
Sieve() { ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
for (int i = 2; i*i <= SZ; ++i) if (!comp[i]) { while (tmp < 0) tmp += b;
for (int j = i*i; j <= SZ; j += i) comp[j] return tmp;
= 1; }
}
} ll naive(ll n, ll m, ll a, ll b) {
bool isprime(int x) { ll x = (a-b)*inv(m,n) % n;
if (x == 1) return 0; ll ans = (m*x+b) % (m*n);
return !comp[x]; while (ans < 0) ans += (m*n);
} return ans;
}; }

void process(ll a, ll n) {
10.1.2 Phi vector<pii> z;
for (int i = 2; i*i <= n; ++i) if (n % i == 0)
{
/** int co = 0;
10. MATH (4) 28

while (n % i == 0) n /= i, co++; }
z.pb({i,co});
} mat operator*(const mat& m) {
if (n != 1) z.pb({n,1}); mat<SZ> a;
for (auto A: z) { F0R(i,SZ) F0R(j,SZ) F0R(k,SZ)
if (M.count(A.f)) { a.d[i][k] = (a.d[i][k]+d[i][j]*m.d[j][k]) %
pii p1 = M[A.f]; MOD;
pii p2 = {A.s,a%(ll)pow(A.f,A.s)}; return a;
if (p1 > p2) swap(p1,p2); }
if (p2.s%(ll)pow(A.f,p1.f) != p1.s) bad
= 1; mat operator^(ll p) {
M[A.f] = p2; mat<SZ> a, b(*this);
} else M[A.f] = {A.s,a%(ll)pow(A.f,A.s)}; F0R(i,SZ) a.d[i][i] = 1;
}
} while (p) {
if (p&1) a = a*b;
ll po(ll b, ll p) { b = b*b;
ll z = 1; p /= 2;
F0R(i,p) z *= b; }
return z;
} return a;
}
pll solve(ll aa, ll nn, ll bb, ll mm) {
bad = 0, M.clear(); void print() {
a = aa, n = nn, b = bb, m = mm; F0R(i,SZ) {
process(a,n), process(b,m); F0R(j,SZ) cout << d[i][j] << " ";
if (bad) { cout << "\n";
cout << "NIE"; }
exit(0); cout << "------------\n";
} }
ll a1 = 0, a2 = 1; };
for (auto& x: M) {
a1 = naive(a2,po(x.f,x.s.f),a1,x.s.s); /*
a2 *= po(x.f,x.s.f); mat<2> x; x.d[0][0] = 1, x.d[1][0] = 2, x.d[1][1] = 1,
} x.d[0][1] = 3;
return {a1,a2}; mat<2> y = x*x;
} mat<2> z = x^5;
}; x.print(), y.print(), z.print();
*/

10.2 Matrices
10.2.2 Gaussian Elimination (6)
10.2.1 Matrix Exponentiation
/**
/** * Description: Gaussian Elimination
* Source: KACTL * Usage:
* Verification: https://dmoj.ca/problem/si17c1p5 https://open.kattis.com/problems/equationsolverplus
*/ */

template<int SZ> struct mat { typedef long double ld;


array<array<ll,SZ>,SZ> d; typedef vector<vector<ld>> mat;

mat() { ld EPS = 1e-10;


F0R(i,SZ) F0R(j,SZ) d[i][j] = 0; int n;
}
void elim(mat& a, int i, int j, int k) {
mat operator+(const mat& m) { ld t = a[k][i];
mat<SZ> a; F0R(ind,n+1) a[k][ind] -= t*a[j][ind];
F0R(i,SZ) F0R(j,SZ) a.d[i][j] = }
(d[i][j]+m.d[i][j]) % MOD;
return a; void prin(mat& a) {
10. MATH (4) 29

F0R(i,n) {
F0R(j,n+1) cout << a[i][j] << " "; template<int SZ> struct Combo {
cout << "\n"; ll fac[SZ+1], ifac[SZ+1];
}
cout << "----\n"; Combo() {
} fac[0] = ifac[0] = 1;
FOR(i,1,SZ+1) {
void solve() { fac[i] = i*fac[i-1] % MOD;
mat a(n); F0R(i,n) a[i].resize(n+1); ifac[i] = inv(fac[i]);
F0R(i,n) F0R(j,n) cin >> a[i][j]; }
F0R(i,n) cin >> a[i][n]; }
int done[n]; F0R(i,n) done[i] = -1;
ll po (ll b, ll p) {
F0R(i,n) { return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD;
F0R(j,n) if (done[j] == -1 && abs(a[j][i]) > }
EPS) {
ld t = a[j][i]; ll inv (ll b) { return po(b,MOD-2); }
F0R(k,n+1) a[j][k] /= t;
ll comb(ll a, ll b) {
F0R(k,n) if (j != k) elim(a,i,j,k); if (a < b) return 0;
done[j] = i; break; ll tmp = fac[a]*ifac[b] % MOD;
} tmp = tmp*ifac[a-b] % MOD;
} return tmp;
}
int num = 0; };
F0R(i,n) if (done[i] == -1) {
num ++;
if (abs(a[i][n]) > EPS) {
10.3.2 Combo Plus
cout << "inconsistent\n";
return;
} /**
} * Description: Extends combo to a power of a prime
ld ans[n]; F0R(i,n) ans[i] = * Verification: https://dmoj.ca/problem/tle17c4p5
numeric_limits<double>::max(); */
F0R(i,n) if (done[i] != -1) {
bool bad = 0; typedef pair<ll,ll> pll;
F0R(j,n) if (j != done[i] && abs(a[i][j]) >
EPS) { template<int SZ> struct ComboExtended {
bad = 1; pll fac[SZ+1], ifac[SZ+1], mod;
break; ll MOD = 1;
}
if (!bad) ans[done[i]] = a[i][n]; void init(pll _mod) { // prime, power
} mod = _mod; F0R(i,mod.s) MOD *= mod.f;
F0R(i,n) {
if (ans[i] != numeric_limits<double>::max()) fac[0] = ifac[0] = {1,0};
cout << ans[i]; FOR(i,1,SZ+1) {
else cout << "?"; fac[i] = fac[i-1];
cout << " "; int I = i, z = 0;
} while (I % mod.f == 0) I /= mod.f, z++;
cout << "\n"; fac[i].f = fac[i].f*I%MOD; fac[i].s += z;
} ifac[i] = {inv(fac[i].f,MOD),fac[i].s};
}
}

10.3 Combinatorics (5) ll inv(ll a, ll b) { // 0 < a < b, gcd(a,b) = 1


a %= b;
10.3.1 Combo Basic
if (a <= 1) return a;
ll i = inv(b%a,a);
/** ll tmp = -((b/a)*i+((b%a)*i)/a) % b;
* Source: Own while (tmp < 0) tmp += b;
* MOD is a large prime return tmp;
*/ }
10. MATH (4) 30

return a;
ll comb(ll a, ll b) { }
if (a < b) return 0;
ll tmp = (fac[a].f*ifac[b].f%MOD)*ifac[a-b].f vd orConv(vd a, vd b) {
% MOD; int s = max(sz(a),sz(b)), L = get(s), n = 1<<L;
ll z = fac[a].s-fac[b].s-fac[a-b].s; if (s <= 0) return {};
if (z >= mod.s) return 0;
F0R(i,z) tmp = tmp*mod.f % MOD; a.resize(n); reverse(all(a)); a = andConv(a);
return tmp; b.resize(n); reverse(all(b)); b = andConv(b);
}
}; F0R(i,n) a[i] = a[i]*b[i];
a = andConv(a,1);
reverse(all(a));
10.4 FFT (6) return a;
}
10.4.1 And Convolution
vl orConv(vl a, vl b) {
/** vd A; for (ll x: a) A.pb(x);
* Description: Similar to FWHT vd B; for (ll x: b) B.pb(x);
* Source: CSA - FFT And Variations vd c = orConv(A,B);
*/ vl C; for (double x: c) C.pb(round(x));
return C;
typedef vector<double> vd; }
typedef vector<ll> vl;
vl conv(vl a, vl b) {
int get(int s) { vd A; for (ll x: a) A.pb(x);
return s > 1 ? 32 - __builtin_clz(s - 1) : 0; vd B; for (ll x: b) B.pb(x);
} vd c = conv(A,B);
vl C; for (double x: c) C.pb(round(x));
namespace andConv { return C;
vd andConv(vd P, bool inv = 0) { }
for (int len = 1; 2 * len <= sz(P); len <<= 1) }
{
for (int i = 0; i < sz(P); i += 2 * len) {
for (int j = 0; j < len; j++) {
10.4.2 Base Conversion
double u = P[i + j];
double v = P[i + len + j];
/**
if (!inv) { * Description: NTT Application
P[i + j] = v; * Usage: 2017 VT HSPC - Alien Codebreaking
P[i + len + j] = u + v; */
} else {
P[i + j] = -u + v; // NTT template
P[i + len + j] = u;
} struct Base {
} vl po10[21];
} const int base = 27;
}
Base() {
return P; po10[0] = {10};
} FOR(i,1,21) {
po10[i] = NTT::conv(po10[i-1],po10[i-1]);
vd conv(vd a, vd b) { normalize(po10[i]);
int s = max(sz(a),sz(b)), L = get(s), n = 1<<L; }
if (s <= 0) return {}; }

a.resize(n); a = andConv(a); void normalize(vl& x) {


b.resize(n); b = andConv(b); F0R(i,sz(x)) if (x[i] >= base) {
if (i == sz(x)-1) x.pb(0);
F0R(i,n) a[i] = a[i]*b[i]; x[i+1] += x[i]/base;
a = andConv(a,1); x[i] %= base;
10. MATH (4) 31

} int t = 2*k%n+j;
while (sz(x) && !x.back()) x.pop_back(); RES[k+j] = res[t]+roots[k]*res[t+inc];
} }
swap(res,RES);
vl convert(vl in) { }
if (sz(in) == 1) return in;
vl l = return res;
convert(vl(in.begin(),in.begin()+sz(in)/2)); }
vl r =
convert(vl(in.begin()+sz(in)/2,in.end())); vcd fft_rev(vcd& a) {
vcd res = fft(a);
r = NTT::conv(r,po10[get(sz(in))-1]); F0R(i,sz(res)) res[i] /= a.size();
normalize(r); reverse(res.begin() + 1, res.end());
return res;
int z = max(sz(l),sz(r)); }
r.resize(z);
F0R(i,sz(l)) r[i] += l[i]; vcd brute(vcd& a, vcd& b) {
normalize(r); vcd c(sz(a)+sz(b)-1);
return r; F0R(i,sz(a)) F0R(j,sz(b)) c[i+j] += a[i]*b[j];
} return c;
}; }

Base B; vcd conv(vcd a, vcd b) {


int s = sz(a)+sz(b)-1, L = get(s), n = 1<<L;
int main() { if (s <= 0) return {};
F0R(i,10) F0R(j,10) F0R(k,10) { if (s <= 200) return brute(a,b);
vl z = {k,j,i};
vl o = B.transform(z); a.resize(n); a = fft(a);
for (ll x: o) cout << x << " "; b.resize(n); b = fft(b);
cout << "\n";
} F0R(i,n) a[i] *= b[i];
} a = fft_rev(a);

a.resize(s);
return a;
10.4.3 FFT
}

/** vl convll(vl a, vl b) {
* Sources: KACTL, https://pastebin.com/3Tnj5mRu vcd A(sz(a)); F0R(i,sz(a)) A[i] = a[i];
* Verification: SPOJ polymul vcd B(sz(b)); F0R(i,sz(b)) B[i] = b[i];
*/ vcd X = conv(A,B);
vl x(sz(X)); F0R(i,sz(X)) x[i] =
typedef complex<double> cd; round(X[i].real());
typedef vector<cd> vcd; return x;
typedef vector<ll> vl; }
}
int get(int s) {
return s > 1 ? 32 - __builtin_clz(s - 1) : 0; int main() {
} int T; cin >> T;
F0R(i,T) {
namespace FFT { int N; cin >> N;
vcd fft(vcd& a) { vl a(N+1), b(N+1);
int n = a.size(), x = get(n); F0R(j,N+1) cin >> a[N-j];
vcd res, RES(n), roots(n); F0R(j,N+1) cin >> b[N-j];
F0R(i,n) roots[i] = vl x = FFT::convll(a,b);
cd(cos(2*M_PI*i/n),sin(2*M_PI*i/n)); F0Rd(j,sz(x)) cout << x[j] << " ";
cout << "\n";
res = a; }
FOR(i,1,x+1) { }
int inc = n>>i;
F0R(j,inc) for (int k = 0; k < n; k += inc)
{
10. MATH (4) 32

10.4.4 NTT F0R(i,sz(a)) F0R(j,sz(b)) c[i+j] =


(c[i+j]+a[i]*b[j])%mod;
return c;
/**
}
* Description: Use if you are working with
non-negative integers
vl conv(vl a, vl b) {
* Verification:
int s = sz(a)+sz(b)-1, L = get(s), n = 1<<L;
http://codeforces.com/contest/632/submission/33953285
if (s <= 0) return {};
*/
if (s <= 200) return brute(a,b);
typedef vector<ll> vl;
a.resize(n); a = ntt(a);
b.resize(n); b = ntt(b);
int get(int s) {
return s > 1 ? 32 - __builtin_clz(s - 1) : 0;
F0R(i,n) a[i] = a[i]*b[i] % mod;
}
a = ntt_rev(a);
namespace NTT {
a.resize(s);
const ll mod = (119 << 23) + 1, root = 3; // =
return a;
998244353
}
// For p < 2^30 there is also e.g. (5 << 25, 3),
}
(7 << 26, 3),
// (479 << 21, 3) and (483 << 21, 5). The last two
int main() {
are > 10^9.
vl X = NTT::conv({1,2,3,4,5,6,7,8},
{1,2,3,4,5,6,7,8});
ll modpow(ll b, ll p) { return
for (auto a: X) cout << a << "\n";
!p?1:modpow(b*b%mod,p/2)*(p&1?b:1)%mod; }
}
ll inv (ll b) { return modpow(b,mod-2); }

vl ntt(vl& a) { 10.4.5 XOR Convolution


int n = a.size(), x = get(n);
vl res, RES(n), roots(n);
/**
roots[0] = 1, roots[1] =
* Description: FWHT, similar to FFT
modpow(root,(mod-1)/n);
* Source: CSA - FFT And Variations
FOR(i,2,n) roots[i] = roots[i-1]*roots[1] %
* Verification:
mod;
https://www.hackerrank.com/challenges/xor-subsequence/pro
*/
res = a;
FOR(i,1,x+1) {
typedef vector<double> vd;
int inc = n>>i;
typedef vector<ll> vl;
F0R(j,inc) for (int k = 0; k < n; k += inc)
{
int get(int s) {
int t = 2*k%n+j;
return s > 1 ? 32 - __builtin_clz(s - 1) : 0;
RES[k+j] = (res[t]+roots[k]*res[t+inc])
}
% mod;
}
namespace FWHT {
swap(res,RES);
vd fwht(vd P) {
}
for (int len = 1; 2 * len <= sz(P); len <<= 1)
{
return res;
for (int i = 0; i < sz(P); i += 2 * len) {
}
for (int j = 0; j < len; j++) {
double u = P[i + j];
vl ntt_rev(vl& a) {
double v = P[i + len + j];
vl res = ntt(a);
P[i + j] = u+v;
ll in = inv(a.size());
P[i + len + j] = u-v;
F0R(i,sz(res)) res[i] = res[i]*in % mod;
}
reverse(res.begin() + 1, res.end());
}
return res;
}
}
return P;
vl brute(vl& a, vl& b) {
}
vl c(sz(a)+sz(b)-1);
11. GRAPHS HARD (4) 33

void addEdge(int a, int b) {


vd fwht_rev(vd& a) { adj[a].pb(b), radj[b].pb(a);
vd res = fwht(a); }
F0R(i,sz(res)) res[i] /= a.size();
return res; void genSCC() {
} FOR(i,1,N+1) comp[i] = visit[i] = 0;
FOR(i,1,N+1) if (!visit[i]) dfs(i);
vd conv(vd a, vd b) { reverse(all(todo)); // toposort
int s = max(sz(a),sz(b)), L = get(s), n = 1<<L; for (int i: todo) if (!comp[i]) {
if (s <= 0) return {}; dfs2(i,i);
allComp.pb(i);
a.resize(n); a = fwht(a); }
b.resize(n); b = fwht(b); }

F0R(i,n) a[i] = a[i]*b[i]; int tmp[SZ];


a = fwht_rev(a); bitset<SZ> ans;
return a;
} bool twosat() {
for (int i = 1; i <= N; i += 2) if (comp[i] ==
vl conv(vl a, vl b) { comp[rev(i)]) return 0;
vd A; for (ll x: a) A.pb(x); reverse(all(allComp));
vd B; for (ll x: b) B.pb(x); for (int i: allComp) if (tmp[i] == 0) {
vd c = conv(A,B); tmp[i] = 1;
vl C; for (double x: c) C.pb(round(x)); tmp[comp[rev(i)]] = -1;
return C; }
} FOR(i,1,N+1) if (tmp[comp[i]] == 1) ans[i]
} = 1;
return 1;
}
};
11 Graphs Hard (4)
11.1 Kosaraju 11.2 Flows
11.2.1 Edmonds-Karp
/**
* Source: Wikipedia
* Description: generates SCC in topological order, /**
support for 2-SAT * Source: GeeksForGeeks
* Verification: POI 8 peaceful commission */
*/
struct Edge {
int rev(int x) { int v;
return x&1?x+1:x-1; ll flow, C;
} int rev;
};
template<int SZ> struct scc {
vi adj[SZ], radj[SZ], todo, allComp; template<int SZ> struct EdmondsKarp {
int N, comp[SZ]; pi pre[SZ];
bitset<SZ> visit; int SC, SNC;
ll flow[SZ];
void dfs(int v) { vector<Edge> adj[SZ];
visit[v] = 1;
for (int w: adj[v]) if (!visit[w]) dfs(w); void addEdge(int u, int v, int C) {
todo.pb(v); Edge a{v, 0, C, sz(adj[v])};
} Edge b{u, 0, 0, sz(adj[u])};
adj[u].pb(a), adj[v].pb(b);
void dfs2(int v, int val) { }
comp[v] = val;
for (int w: radj[v]) if (!comp[w]) dfs2(w,val); bool bfs() {
} memset(flow,0,sizeof flow);
flow[SC] = INF;
11. GRAPHS HARD (4) 34

* Code: https://pastebin.com/VJxTvEg1
queue<int> todo; todo.push(SC); */
while (todo.size()) {
if (flow[SNC]) break; struct Edge {
int x = todo.front(); todo.pop(); int v;
for (auto a: adj[x]) if (!flow[a.v] && ll flow, C;
a.flow < a.C) { int rev;
pre[a.v] = {x,a.rev}; };
flow[a.v] = min(flow[x],a.C-a.flow);
todo.push(a.v); template<int SZ> struct Dinic {
} int level[SZ], start[SZ];
} vector<Edge> adj[SZ];

return flow[SNC]; void addEdge(int u, int v, int C) {


} Edge a{v, 0, C, sz(adj[v])};
Edge b{u, 0, 0, sz(adj[u])};
ll maxFlow(int sc, int snc) { adj[u].pb(a), adj[v].pb(b);
SC = sc, SNC = snc; }

ll ans = 0; bool bfs(int s, int t) {


while (bfs()) { F0R(i,SZ) level[i] = -1;
ans += flow[SNC]; level[s] = 0;
for (int x = SNC; x != SC; x = pre[x].f) {
adj[x][pre[x].s].flow -= flow[SNC]; queue<int> q; q.push(s);
int t = adj[x][pre[x].s].rev; while (!q.empty()) {
adj[pre[x].f][t].flow += flow[SNC]; int u = q.front(); q.pop();
} for (auto e: adj[u])
} if (level[e.v] < 0 && e.flow < e.C) {
level[e.v] = level[u] + 1;
return ans; q.push(e.v);
} }
}; }

return level[t] >= 0;


}
11.2.2 Flows Demo
ll sendFlow(int u, ll flow, int t) {
/** if (u == t) return flow;
* Link: http://www.spoj.com/problems/FASTFLOW/
* Use with Dinic, Push-Relabel, Edmonds-Karp for ( ; start[u] < sz(adj[u]); start[u] ++) {
*/ Edge &e = adj[u][start[u]];

int N,M; if (level[e.v] == level[u]+1 && e.flow <


PushRelabel<5001> D; e.C) {
ll curr_flow = min(flow, e.C - e.flow);
int main() { ll temp_flow = sendFlow(e.v, curr_flow,
cin >> N >> M; t);
F0R(i,M) {
int a,b,c; cin >> a >> b >> c; if (temp_flow > 0) {
D.addEdge(a,b,c); e.flow += temp_flow;
D.addEdge(b,a,c); adj[e.v][e.rev].flow -= temp_flow;
} return temp_flow;
cout << D.maxFlow(1,N); }
} }
}

11.2.3 Dinic (5) return 0;


}

/** ll maxFlow(int s, int t) {


* Source: GeeksForGeeks if (s == t) return -1;
* Verification: Problem Fashion (RMI 2017 Day 1) ll total = 0;
11. GRAPHS HARD (4) 35

enqueue(v);
while (bfs(s, t)) { }
F0R(i,SZ) start[i] = 0; }
while (ll flow = sendFlow(s, INT_MAX, t))
total += flow; void relabel (int v) {
} count[dist[v]] --; dist[v] = SZ;
for (auto e: adj[v]) if (e.C > e.flow) dist[v]
return total; = min(dist[v], dist[e.v] + 1);
} count[dist[v]] ++;
}; enqueue(v);
}

void discharge(int v) {
11.2.4 Push-Relabel (5)
for (auto &e: adj[v]) {
if (excess[v] > 0) push(v,e);
/** else break;
* Source: http://codeforces.com/blog/entry/14378 }
* Verification: SPOJ fastflow if (excess[v] > 0) {
*/ if (count[dist[v]] == 1) gap(dist[v]);
else relabel(v);
struct Edge { }
int v; }
ll flow, C;
int rev; ll maxFlow (int s, int t) {
}; for (auto &e: adj[s]) excess[s] += e.C;

template <int SZ> struct PushRelabel { count[0] = SZ;


vector<Edge> adj[SZ]; enqueue(s); active[t] = 1;
ll excess[SZ];
int dist[SZ], count[SZ+1], b = 0; while (b >= 0) {
bool active[SZ]; if (sz(B[b])) {
vi B[SZ]; int v = B[b].back(); B[b].pop_back();
active[v] = 0; discharge(v);
void addEdge(int u, int v, int C) { } else b--;
Edge a{v, 0, C, sz(adj[v])}; }
Edge b{u, 0, 0, sz(adj[u])}; return excess[t];
adj[u].pb(a), adj[v].pb(b); }
} };

void enqueue (int v) {


if (!active[v] && excess[v] > 0 && dist[v] <
11.2.5 MinCostFlow (6)
SZ) {
active[v] = 1;
B[dist[v]].pb(v); /**
b = max(b, dist[v]); * Source: GeeksForGeeks
} */
}
struct Edge {
void push (int v, Edge &e) { int v, flow, C, rev, cost;
ll amt = min(excess[v], e.C-e.flow); };
if (dist[v] == dist[e.v]+1 && amt > 0) {
e.flow += amt, adj[e.v][e.rev].flow -= amt; template<int SZ> struct mcf {
excess[e.v] += amt, excess[v] -= amt; pii pre[SZ];
enqueue(e.v); int cost[SZ], num[SZ], SC, SNC;
} ll flo, ans, ccost;
} vector<Edge> adj[SZ];

void gap (int k) { void addEdge(int u, int v, int C, int cost) {


F0R(v,SZ) if (dist[v] >= k) { Edge a{v, 0, C, sz(adj[v]), cost};
count[dist[v]] --; Edge b{u, 0, 0, sz(adj[u]), -cost};
dist[v] = SZ; adj[u].pb(a), adj[v].pb(b);
count[dist[v]] ++; }
11. GRAPHS HARD (4) 36

void reweight() {
F0R(i,SZ) {
for (auto& p: adj[i]) p.cost += 11.3 Tarjan BCC
cost[i]-cost[p.v];
}
} /**
* Source: GeeksForGeeks (corrected)
bool spfa() { * Verification: USACO December 2017, Push a Box
F0R(i,SZ) cost[i] = MOD, num[i] = 0; * Code: https://pastebin.com/yUWuzTH8
cost[SC] = 0, num[SC] = MOD; */
priority_queue<pii,vector<pii>,greater<pii>>
todo; todo.push({0,SC}); template<int SZ> struct BCC {
int N, ti = 0;
while (todo.size()) { vi adj[SZ];
pii x = todo.top(); todo.pop(); int disc[SZ], low[SZ], comp[SZ], par[SZ];
if (x.f > cost[x.s]) continue; vector<vector<pii>> fin;
for (auto a: adj[x.s]) if (x.f+a.cost < vector<pii> st;
cost[a.v] && a.flow < a.C) {
pre[a.v] = {x.s,a.rev}; void addEdge(int u, int v) {
cost[a.v] = x.f+a.cost; adj[u].pb(v), adj[v].pb(u);
num[a.v] = min(a.C-a.flow,num[x.s]); }
todo.push({cost[a.v],a.v});
} void BCCutil(int u) {
} disc[u] = low[u] = ti++;
int child = 0;
ccost += cost[SNC];
return num[SNC] > 0; for (int i: adj[u]) if (i != par[u]) {
} if (disc[i] == -1) {
child ++; par[i] = u;
void backtrack() { st.pb({u,i});
flo += num[SNC], ans += (ll)num[SNC]*ccost; BCCutil(i);
for (int x = SNC; x != SC; x = pre[x].f) { low[u] = min(low[u],low[i]);
adj[x][pre[x].s].flow -= num[SNC];
int t = adj[x][pre[x].s].rev; if ((disc[u] == 0 && child > 1) ||
adj[pre[x].f][t].flow += num[SNC]; (disc[u] != 0 && disc[u] <=
} low[i])) { // articulation point!
} vector<pii> tmp;
while (st.back() != mp(u,i))
pii mincostflow(int sc, int snc) { tmp.pb(st.back()),
SC = sc, SNC = snc; st.pop_back();
flo = ans = ccost = 0; tmp.pb(st.back()), st.pop_back();
fin.pb(tmp);
spfa(); }
while (1) { } else if (disc[i] < disc[u]) {
reweight(); low[u] = min(low[u],disc[i]);
if (!spfa()) return {flo,ans}; st.pb({u,i});
backtrack(); }
} }
} }
};
void bcc() {
mcf<100> m; FOR(i,1,N+1) par[i] = disc[i] = low[i] = -1;
FOR(i,1,N+1) if (disc[i] == -1) {
int main() { BCCutil(i);
m.addEdge(0, 1, 16, 5); if (sz(st)) fin.pb(st);
m.addEdge(1, 2, 13, 7); st.clear();
m.addEdge(1, 2, 13, 8); }
}
pii x = m.mincostflow(0,2); };
cout << x.f << " " << x.s;
}
12. GEOMETRY (4) 37

11.4 Euler Tour (6) 12 Geometry (4)


/** 12.1 Techniques
* Description: extra log factor
* Usage: https://open.kattis.com/problems/eulerianpath 12.1.1 Pair Operators
*/
/**
vi circuit;
* Source: own
multiset<int> adj[10000], adj1[10000];
*/
int N,M, out[10000], in[10000];
template<class T> pair<T,T> operator+(const pair<T,T>&
void find_circuit(int x) { // directed graph, possible
l, const pair<T,T>& r) {
that resulting circuit is not valid
return {l.f+r.f,l.s+r.s};
while (adj[x].size()) {
}
int j = *adj[x].begin();
adj[x].erase(adj[x].begin());
template<class T> pair<T,T> operator-(const pair<T,T>&
find_circuit(j);
l, const pair<T,T>& r) {
}
return {l.f-r.f,l.s-r.s};
circuit.pb(x);
}
}
template<class T> pair<T,T> operator*(const pair<T,T>&
int a,b,start;
l, T r) {
return {l.f*r,l.s*r};
void solve() {
}
F0R(i,N) {
adj[i].clear(), adj1[i].clear();
template<class T> pair<T,T> operator/(const pair<T,T>&
out[i] = in[i] = 0;
l, T r) {
}
return {l.f/r,l.s/r};
circuit.clear();
}
F0R(i,M) {
cin >> a >> b;
template<class T> double mag(pair<T,T> p) {
adj[a].insert(b), adj1[a].insert(b);
return sqrt(p.f*p.f+p.s*p.s);
out[a] ++, in[b] ++;
}
}
start = a;
template<class T> pair<T,T> operator*(const pair<T,T>&
F0R(i,N) if (out[i]-in[i] == 1) start = i;
l, const pair<T,T>& r) {
// l.f+l.s*i, r.f+r.s*i
find_circuit(start);
return {l.f*r.f-l.s*r.s,l.s*r.f+l.f*r.s};
reverse(circuit.begin(),circuit.end());
}
if (circuit.size() != M+1) {
template<class T> pair<T,T> operator/(const pair<T,T>&
cout << "Impossible\n";
l, const pair<T,T>& r) {
return;
// l.f+l.s*i, r.f+r.s*i
}
pair<T,T> z =
{r.f/(r.f*r.f+r.s*r.s),-r.s/(r.f*r.f+r.s*r.s)};
F0R(i,M) {
return l*z;
if (adj1[circuit[i]].find(circuit[i+1]) ==
}
adj1[circuit[i]].end()) {
cout << "Impossible\n";
template<class T> double area(pair<T,T> a, pair<T,T>
return;
b, pair<T,T> c) {
}
b = b-a, c = c-a;
int t = circuit[i];
return (b.f*c.s-b.s*c.f)/2;
adj1[t].erase(adj1[t].find(circuit[i+1]));
}
}
F0R(i,M+1) cout << circuit[i] << " ";
template<class T> double dist(pair<T,T> l, pair<T,T>
cout << "\n";
r) {
}
return mag(r-l);
}

template<class T> double dist(pair<T,T> o, pair<T,T>


x, pair<T,T> d) { // signed distance
12. GEOMETRY (4) 38

return 2*area(o,x,x+d)/mag(d); int a1 = sgn(A,B,C), a2 = sgn(A,B,D);


} if (a1 > a2) swap(a1,a2);
if (!(a1 <= 0 && a2 >= 0)) {
cout << "none\n";
return;
12.1.2 Polygon Area
}
if (a1 == 0 && a2 == 0) {
/** if (sgn(A,C,D) != 0) {
* Description: Shoelace Formula cout << "none\n";
* Usage: https://open.kattis.com/problems/polygonarea return;
*/ }
pii x1 = max(A,C), x2 = min(B,D);
double area(vector<pii> v) { if (x1 > x2) cout << "none\n";
double x = 0; else if (x1 == x2) cout << (double)x1.f << " "
F0R(i,sz(v)) { << (double)x1.s << "\n";
int j = (i+1)%sz(v); else cout << (double)x1.f << " " <<
x += (ll)v[i].f*v[j].s; (double)x1.s << " " << (double)x2.f << " "
x -= (ll)v[j].f*v[i].s; << (double)x2.s << "\n";
} return;
return abs(x)/2; }
} pdd z = get(A,B,C,D);
if (mp((double)A.f,(double)A.s) <= z && z <=
mp((double)B.f,(double)B.s)) cout << z.f << "
12.1.3 Line Segment Intersection (5) " << z.s << "\n";
else cout << "none\n";
}
/**
* Verification: Kattis segmentintersection int main() {
* If numbers are small enough, fractions are int n; cin >> n;
recommended. cout << fixed << setprecision(2);
*/ F0R(i,n) solve();
}
typedef pair<double,double> pdd;

pii A,B,C,D;
12.1.4 Point in Polygon (5)
pdd operator*(int x, pdd y) {
return {x*y.f,x*y.s}; /**
} * Source: own
* Usage:
pdd operator/(pdd y, int x) { https://open.kattis.com/problems/pointinpolygon
return {y.f/x,y.s/x}; */
}
int n,m;
pdd operator+(pdd l, pdd r) { pii p[1000];
return {l.f+r.f,l.s+r.s};
} int area(pii x, pii y, pii z) {
return (y.f-x.f)*(z.s-x.s)-(y.s-x.s)*(z.f-x.f);
int sgn(pii a, pii b, pii c) { }
return (b.s-a.s)*(c.f-a.f)-(b.f-a.f)*(c.s-a.s);
} bool on(pii x, pii y, pii z) {
if (area(x,y,z) != 0) return 0;
pdd get(pii a, pii b, pii c, pii d) { return min(x,y) <= z && z <= max(x,y);
return (abs(sgn(a,b,c))*d+abs(sgn(a,b,d))*c) }
/(abs(sgn(a,b,c))+abs(sgn(a,b,d)));
} double get(pii x, pii y, int z) {
return double((z-x.s)*y.f+(y.s-z)*x.f)/(y.s-x.s);
void solve() { }
cin >> A.f >> A.s >> B.f >> B.s >> C.f >> C.s >>
D.f >> D.s; void test(pii z) {
if (A > B) swap(A,B); int ans = 0;
if (C > D) swap(C,D); F0R(i,n) {
12. GEOMETRY (4) 39

pii x = p[i], y = p[(i+1)%n];


if (on(x,y,z)) { bool coplanar(vl a, vl b, vl c, vl d) {
cout << "on\n"; b = b-a, c = c-a, d = d-a;
return; return ismult(cross(b,c),cross(b,d));
} }
if (x.s > y.s) swap(x,y);
if (x.s <= z.s && y.s > z.s) {
double t = get(x,y,z.s);
12.1.6 Circles (6)
if (t > z.f) ans++;
}
} /**
if (ans % 2 == 1) cout << "in\n"; * Source: Own
else cout << "out\n"; * Usage:
} https://codefights.com/tournaments/s8thqrnQL2YPK7XQt/L
*/
void solve() {
F0R(i,n) cin >> p[i].f >> p[i].s; typedef complex<double> cd;
cin >> m; typedef pair<cd,double> circle;
F0R(i,m) {
pii z; cin >> z.f >> z.s; cd intersect(circle a, circle b, int x = 0) {
test(z); double d = sqrt(norm(a.f-b.f));
} double co = (a.s*a.s+d*d-b.s*b.s)/(2*a.s*d);
} double theta = acos(co);

cd tmp = (b.f-a.f)/d;
if (x == 0) return a.f+tmp*a.s*polar(1.0,theta);
12.1.5 3D Geometry (6)
return a.f+tmp*a.s*polar(1.0,-theta);
}
/**
* Description: Basic 3D Geometry double arc(circle x, cd a, cd b) {
* Usage: AMPPZ 2011 Cross Spider cd d = (a-x.f)/(b-x.f);
*/ return x.s*acos(d.real());
}
typedef vector<ll> vl;
bool on (circle x, cd y) {
typedef long double ld; return norm(y-x.f) == x.s*x.s;
}
int n;
vector<vl> cur; int main() {
cout << intersect({0,2},{1,1}) << "\n";
vl operator-(vl a, vl b) { cout << arc({0,1},cd(1,0),cd(0,1)) << "\n";
vl c(sz(a)); F0R(i,sz(a)) c[i] = a[i]-b[i]; cout << on({0,1},1) << "\n";
return c; }
}

bool ismult(vl b, vl c) {
if ((ld)b[0]*c[1] != (ld)b[1]*c[0]) return 0; 12.2 Sweep Line
if ((ld)b[0]*c[2] != (ld)b[2]*c[0]) return 0;
12.2.1 Convex Hull
if ((ld)b[2]*c[1] != (ld)b[1]*c[2]) return 0;
return 1;
} /**
* Source: Wikibooks
bool collinear(vl a, vl b, vl c) { * Usage: https://open.kattis.com/problems/convexhull
b = b-a, c = c-a; */
return ismult(b,c);
} ll cross(pii O, pii A, pii B) {
return (ll)(A.f-O.f)*(B.s-O.s)
vl cross(vl a, vl b) { -(ll)(A.s-O.s)*(B.f-O.f);
return {a[1]*b[2]-a[2]*b[1], }
a[2]*b[0]-a[0]*b[2],
a[0]*b[1]-a[1]*b[0]}; vector<pii> convex_hull(vector<pii> P) {
}
12. GEOMETRY (4) 40

sort(P.begin(),P.end()); }
P.erase(unique(P.begin(),P.end()),P.end());
if (P.size() == 1) return P; pair<double,pair<pdd,pdd>> strip(vector<pdd> v, double
di) {
int n = P.size(); pair<double,pair<pdd,pdd>> ans = MN;
F0R(i,v.size()) FOR(j,i+1,v.size()) {
vector<pii> bot = {P[0]}; if (v[i].s+di <= v[j].s) break;
FOR(i,1,n) { ans = min(ans,{dist(v[i],v[j]),{v[i],v[j]}});
while (bot.size() > 1 && }
cross(bot[bot.size()-2], bot.back(), P[i]) return ans;
<= 0) bot.pop_back(); }
bot.pb(P[i]);
} pair<double,pair<pdd,pdd>> bes (vector<pdd> v) {
bot.pop_back(); if (v.size() == 1) return MN;
int M = v.size()/2;
vector<pii> up = {P[n-1]}; vector<pdd> v1(v.begin(),v.begin()+M),
F0Rd(i,n-1) { v2(v.begin()+M,v.end());
while (up.size() > 1 && cross(up[up.size()-2], auto a = bes(v1), b = bes(v2);
up.back(), P[i]) <= 0) up.pop_back(); double di = min(a.f,b.f);
up.pb(P[i]);
} vector<pdd> V;
up.pop_back(); F0R(i,v.size()) if (v[i].f > v[M].f-di && v[i].f <
v[M].f+di) V.pb(v[i]);
bot.insert(bot.end(),all(up)); sort(V.begin(),V.end(),cmp);
return bot;
} auto z = strip(V,di);
return min(min(a,b),z);
int main() { }
int n;
while (cin >> n) { int main() {
if (n == 0) break; cout << fixed << setprecision(2);
vector<pii> P(n); F0R(i,n) cin >> P[i].f >> while (cin >> n) {
P[i].s; if (n == 0) break;
vector<pii> hull = convex_hull(P); vector<pdd> v(n);
F0R(i,n) cin >> v[i].f >> v[i].s;
cout << hull.size() << "\n"; sort(v.begin(),v.end());
for (auto a: hull) cout << a.f << " " << a.s auto a = bes(v);
<< "\n"; cout << a.s.f.f << " " << a.s.f.s << " " <<
} a.s.s.f << " " << a.s.s.s << "\n";
} }
}

12.2.2 Closest Pair (6)


12.2.3 LineContainer (6)
/**
* Source: GeeksForGeeks /**
* Description: Nlog^2N, can be improved * Source: KACTL
* Use: https://open.kattis.com/problems/closestpair2 * Verification: CSA Squared Ends
*/ */

pair<double,pair<pdd,pdd>> MN = {INF,{{0,0},{0,0}}}; bool Q;


struct Line {
int n; mutable ll k, m, p; // slope, y-intercept,
last optimal x
bool cmp(pdd a, pdd b) { bool operator<(const Line& o) const {
return a.s < b.s; return Q ? p < o.p : k < o.k;
} }
};
double dist(pdd a, pdd b) {
b.f -= a.f, b.s -= a.s; struct LineContainer : multiset<Line> {
return sqrt(b.f*b.f+b.s*b.s); const ll inf = LLONG_MAX;
13. ADDITIONAL (4) 41

ll div(ll a, ll b) { // floored division FOR(i,1,n+1) if (i*(i-1)/2 <= mx) ans = i;


if (b < 0) a *= -1, b *= -1; cout << ans << "\n";
if (a >= 0) return a/b; }
return -((-a+b-1)/b);
}

// updates x->p, determines if y is unneeded 13 Additional (4)


bool isect(iterator x, iterator y) {
if (y == end()) { x->p = inf; return 0;
}
13.1 Mo
if (x->k == y->k) x->p = x->m > y->m ?
inf : -inf; /**
else x->p = div(y->m - x->m, x->k - * Source: Codeforces
y->k); * Description: Answers queries offline in (N+Q)sqrt(N)
return x->p >= y->p; * Also see Mo’s on trees
} */

void add(ll k, ll m) { int block = 300; // set ~sqrt(N)


auto z = insert({k, m, 0}), y = z++, x
= y; bool cmp(vi a, vi b) {
while (isect(y, z)) z = erase(z); if (a[0]/block != b[0]/block) return a[0] < b[0];
if (x != begin() && isect(--x, y)) return a[1] < b[1];
isect(x, y = erase(y)); }
while ((y = x) != begin() && (--x)->p
>= y->p) isect(x, erase(y));
}
13.2 Misc
ll query(ll x) { // gives max value 13.2.1 Discrete Logarithm
assert(!empty());
Q = 1; auto l = *lb({0,0,x}); Q = 0;
return l.k * x + l.m; /**
} * Description: find k such that primitive^k=x
}; * meet in the middle, O(sqrt(MOD))
* Source: Own
* Verification: PA 2006 - Professor Laugh’s Numbers
*/
12.3 Max Collinear
const int BLOCK = 32000;
/**
* Source: own int primitive = 5, invy[BLOCK];
* Usage: https://open.kattis.com/problems/maxcolinear unordered_map<int,int> u;
*/
ll po (ll b, ll p) {
int n, mx, ans; return !p?1:po(b*b%MOD,p/2)*(p&1?b:1)%MOD;
map<pair<pii,int>,int> m; }
pii p[1000];
ll inv (ll b) { return po(b,MOD-2); }
pair<pii,int> getline(pii a, pii b) {
pii z = {b.f-a.f,b.s-a.s}; ll query(int x) {
swap(z.f,z.s); z.f *= -1; F0R(i,BLOCK) if (u.count(x*invy[i]%MOD))
int g = __gcd(z.f,z.s); z.f /= g, z.s /= g; return i*BLOCK+u[x*invy[i]%MOD];
if (z.f < 0 || (z.f == 0 && z.s < 0)) z.f *= -1, return -1;
z.s *= -1; }
return {z,z.f*a.f+z.s*a.s};
} int main() {
ll cur = 1;
void solve() { F0R(i,BLOCK) {
mx = ans = 0; m.clear(); u[cur] = i;
F0R(i,n) cin >> p[i].f >> p[i].s; cur = primitive*cur%MOD;
F0R(i,n) FOR(j,i+1,n) m[getline(p[i],p[j])] ++; }
ll t = 1;
for (auto a: m) mx = max(mx,a.s); F0R(i,BLOCK) {
13. ADDITIONAL (4) 42

invy[i] = inv(t);
t = t*cur%MOD;
}
ll x; cin >> x;
cout << query(x) << "\n";
}

13.3 Pragma Optimization (6)

/**
* Source: Misc solutions to CF Nagini
* Description: 10^{10} operations are ok!
* Passes the occasional disgusting CF task
* Also see "Welcome home, Chtholly"
*/

#pragma GCC optimize ("O3")


#pragma GCC target ("sse4")

int q, mx[100001], mn[100001];

int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> q;
F0R(i,100001) mx[i] = -MOD, mn[i] = MOD;
F0R(i,q) {
int t,l,r,k; cin >> t >> l >> r;
r -= l;

auto a = mx+l, b = mn+l;


if (t == 1) {
cin >> k;
if (k > 0) F0R(j,r) b[j] = min(b[j],k);
else F0R(j,r) a[j] = max(a[j],k);
} else {
ll ans = 0;
F0R(j,r) if (a[j] != -MOD && b[j] != MOD)
ans += b[j]-a[j];
cout << ans << "\n";
}
}
}

You might also like