0% found this document useful (0 votes)
5 views40 pages

Latex

Uploaded by

aimantahmid100
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)
5 views40 pages

Latex

Uploaded by

aimantahmid100
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/ 40

Pablo Messina’s ICPC Notebook CONTENTS - CONTENTS Página 1 de 40

Contents 7.6 Lowest Commen Ancestor (LCA) . . . . . . . . . . . . . . . . . . . . . . 23


7.7 Diameter of a Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
1 C++ Template 2 7.8 Articulation Points, Cut Edges, Biconnected Components . . . . . . . . 25
7.9 Strongly Connected Components . . . . . . . . . . . . . . . . . . . . . . 26
2 C++ Cheat Sheet 2 7.10 Max Flow : Dinic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3 Data Structures 4 8 Mathematics 27
3.1 C++ STL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 8.1 Euclidean Algorithm . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
3.1.1 Pairs & Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 8.2 Primality Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
3.1.2 Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 8.3 Prime Factorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.1.3 Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 8.4 Binary modular exponentiation . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.4 Queue & Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 8.5 Modular Binomial Coefficient . . . . . . . . . . . . . . . . . . . . . . . . 30
3.1.5 Priority Queue . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 8.6 Modular Multinomial Coefficient . . . . . . . . . . . . . . . . . . . . . . 30
3.1.6 Set & Multiset . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 8.7 Chinese Remainder Theorem (CRT) . . . . . . . . . . . . . . . . . . . . 31
3.1.7 Map & Multimap . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8.8 Theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.1.8 Unordered Set & Multiset . . . . . . . . . . . . . . . . . . . . . . 9 8.8.1 Pick’s Theorem . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.1.9 Unordered Map & Multimap . . . . . . . . . . . . . . . . . . . . 10
3.1.10 Deque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 9 Geometry 32
3.1.11 List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 9.1 Geometry 2D Utils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
3.1.12 Policy based Data Structures: Ordered Set . . . . . . . . . . . . 11 9.2 Geometry 3D Utils . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
3.1.13 Bitset . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 9.3 Polygon Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2 Sparse Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 9.4 Trigonometry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3 Fenwick Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 9.5 Convex Hull . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.4 Fenwick Tree 2D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 9.6 Green’s Theorem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.5 Segment Tree . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.6 Segment Tree Lazy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 10 Strings 37
3.7 Union-Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 10.1 Suffix Array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
10.2 Trie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4 Binary Search 16 10.3 Rolling Hashing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
10.4 KMP (Knuth Morris Pratt) . . . . . . . . . . . . . . . . . . . . . . . . . 39
5 Ternary Search 17 10.5 Shortest Repeating Cycle . . . . . . . . . . . . . . . . . . . . . . . . . . 40

6 Dynamic Programming 17
6.1 Longest Increasing Subsequence . . . . . . . . . . . . . . . . . . . . . . . 17
6.2 Travelling Salesman Problem . . . . . . . . . . . . . . . . . . . . . . . . 17
6.3 Knapsack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
6.4 Divide & Conquer Optimization . . . . . . . . . . . . . . . . . . . . . . 19

7 Graphs 20
7.1 BFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.2 DFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
7.3 TopoSort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.4 Dijkstra . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
7.5 Minimum Spanning Tree (Kruskal & Prim) . . . . . . . . . . . . . . . . 22
Pablo Messina’s ICPC Notebook 2 C++ CHEAT SHEET - Página 2 de 40
1 C++ Template 29 ss >> y; // y = 12345678910
30
31 // 2) stoi, stoll
1 #pragma GCC optimize("Ofast") 32 string str_dec = "2001, A Space Odyssey";
2 #include <bits/stdc++.h> 33 string str_hex = "40c3";
3 using namespace std; 34 string str_bin = "-10010110001";
4 // defines 35 string str_auto = "0x7f";
5 #define rep(i,a,b) for(int i = a; i <= b; ++i) 36 int sz;
6 #define invrep(i,b,a) for(int i = b; i >= a; --i) 37 int i_dec = stoi(str_dec,&sz);
7 #define umap unordered_map 38 int i_hex = stoi(str_hex,0,16);
8 #define uset unordered_set 39 int i_bin = stoi(str_bin,0,2);
9 // typedefs; 40 int i_auto = stoi(str_auto,0,0);
10 typedef unsigned long long int ull; 41 cout << str_dec << ": " << i_dec << " and [" << str_dec.substr(sz) << "]\n";
11 typedef long long int ll; 42 cout << str_hex << ": " << i_hex << ’\n’;
12 typedef vector<int> vi; 43 cout << str_bin << ": " << i_bin << ’\n’;
13 typedef pair<int,int> ii; 44 cout << str_auto << ": " << i_auto << ’\n’;
14 // ------------------------------- 45 // 2001, A Space Odyssey: 2001 and [, A Space Odyssey]
15 int main() { 46 // 40c3: 16579
16 ios::sync_with_stdio(false); 47 // -10010110001: -1201
17 cin.tie(0); cout.tie(0); 48 // 0x7f: 127
18 return 0; 49 string str = "8246821 0xffff 020";
19 } 50 int sz = 0;
51 while (!str.empty()) {
2 C++ Cheat Sheet 52
53
long long ll = stoll(str,&sz,0);
cout << str.substr(0,sz) << " interpreted as " << ll << ’\n’;
54 str = str.substr(sz);
1 /* ================================= */ 55 }
2 /* Input/Output with C++: cin & cout */ 56 // 8246821 interpreted as 8246821
3 /* ================================= */ 57 // 0xffff interpreted as 65535
4 58 // 020 interpreted as 16
5 // reading many lines of unknown length 59

6 string line; 60 /* ========================== */


7 while(getline(cin, line)) {} 61 /* C STRING UTILITY FUNCTIONS */
8 62 /* ========================== */
9 // reading tokens from a line 63 int strcmp ( const char * str1, const char * str2 ); // (-1,0,1)
10 string token; 64 int memcmp ( const void * ptr1, const void * ptr2, size_t num ); // (-1,0,1)
11 stringstream ss(line); 65 void * memcpy ( void * destination, const void * source, size_t num );
12 while (ss >> token) { /* do something with token */} 66

13 67 /* ============================ */
14 // printing floating with fixed precision 68 /* C++ STRING UTILITY FUNCTIONS */
15 cout << setprecision(6) << fixed; 69 /* ============================ */
16 cout << 12312.12312355; 70

17 71 // split a string by a single char delimiter


18 /* ================================= */ 72 void split(const string &s, char delim, vector<string> &elems) {
19 /* CONVERTING FROM STRING TO NUMBERS */ 73 stringstream ss(s);
20 /* ================================= */ 74 string item;
21 75 while (getline(ss, item, delim))
22 // 1) stringstream 76 elems.push_back(item);
23 string s = "12345"; 77 }
24 stringstream ss(s); 78

25 int x; 79 // find index of string or char within string


26 ss >> x; // x = 12345 80 string str = "random";
27 ss << "12345678910"; 81 size_t pos = str.find("ra");
28 long long y; 82 size_t pos = str.find(’m’);
Pablo Messina’s ICPC Notebook 2 C++ CHEAT SHEET - Página 3 de 40
83 if (pos == string::npos) // not found 137 return a.y < b.y;
84 138 }
85 // substrings 139 bool operator>(const Point& a, const Point& b) {
86 string subs = str.substr(pos, length); 140 if (a.x != b.x) return a.x > b.x;
87 string subs = str.substr(pos); // default: to the end of the string 141 return a.y > b.y;
88 142 }
89 // std::string from cstring’s substring 143 bool operator==(const Point& a, const Point& b) {
90 const char* s = "bla1 bla2"; 144 return a.x == b.x && a.y == b.y;
91 int offset = 5, len = 4; 145 }
92 string subs(s + offset, len); // bla2 146 // Note: if you overload the < operator for a custom struct,
93 147 // then you can use that struct with any library function
94 // ------------------------- 148 // or data structure that requires the < operator
95 // string comparisons 149 // Examples:
96 string str1("green apple"); 150 priority_queue<Point> pq;
97 string str2("red apple"); 151 vector<Point> pts;
98 if (str1.compare(str2) != 0) 152 sort(pts.begin(), pts.end());
99 cout << str1 << " is not " << str2 << ’\n’; 153 lower_bound(pts.begin(), pts.end(), {1,2});
100 if (str1.compare(6,5,"apple") == 0) 154 upper_bound(pts.begin(), pts.end(), {1,2});
101 cout << "still, " << str1 << " is an apple\n"; 155 set<Point> pt_set;
102 if (str2.compare(str2.size()-5,5,"apple") == 0) 156 map<Point, int> pt_map;
103 cout << "and " << str2 << " is also an apple\n"; 157
104 if (str1.compare(6,5,str2,4,5) == 0) 158 /* =============== */
105 cout << "therefore, both are apples\n"; 159 /* RANDOM INTEGERS */
106 // green apple is not red apple 160 /* =============== */
107 // still, green apple is an apple 161 #include <cstdlib>
108 // and red apple is also an apple 162 #include <ctime>
109 // therefore, both are apples 163 srand(time(NULL));
110 164 int x = rand() % 100; // 0-99
111 /* ===================== */ 165 int randBetween(int a, int b) { // a-b
112 /* OPERATOR OVERLOADING */ 166 return a + (rand() % (1 + b - a));
113 /* ===================== */ 167 }
114 168
115 //-------------------------- 169 /* ============== */
116 // method #1: inside struct 170 /* Bitwise Tricks */
117 struct Point { 171 /* ============== */
118 int x, y; 172 // amount of one-bits in number
119 bool operator<(const Point& p) const { 173 int __builtin_popcount(int x);
120 if (x != p.x) return x < p.x; 174 int __builtin_popcountl(long x);
121 return y < p.y; 175 int __builtin_popcountll(long long x);
122 } 176 // amount of leading zeros in number
123 bool operator>(const Point& p) const { 177 int __builtin_clz(int x);
124 if (x != p.x) return x > p.x; 178 int __builtin_clzl(long x);
125 return y > p.y; 179 int __builtin_clzll(ll x);
126 } 180 // binary length of non-negative number
127 bool operator==(const Point& p) const { 181 int bitlen(int x) { return sizeof(x) * 8 - __builtin_clz(x); }
128 return x == p.x && y == p.y; 182 int bitlen(ll x) { return sizeof(x) * 8 - __builtin_clzll(x); }
129 } 183 // index of most significant bit
130 }; 184 int log2(int x) { return sizeof(x) * 8 - __builtin_clz(x) - 1; }
131 185 int log2(ll x) { return sizeof(x) * 8 - __builtin_clzll(x) - 1; }
132 //-------------------------- 186 // reverse the bits of an integer
133 // method #2: outside struct 187 int reverse_bits(int x) {
134 struct Point {int x, y; }; 188 int v = 0;
135 bool operator<(const Point& a, const Point& b) { 189 while (x) v <<= 1, v |= x&1, x >>= 1;
136 if (a.x != b.x) return a.x < b.x; 190 return v;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - Página 4 de 40
191 } 8 //======
192 // get string binary representation of an integer 9 // Example: pair of ints
193 string bitstring(int x) { 10 typedef pair<int,int> ii; // use ii as abbreviation
194 int len = sizeof(x) * 8 - __builtin_clz(x); 11 // initialization
195 if (len == 0) return "0"; 12 ii p(5,5); // option 1
196 13 ii p = make_pair(5,5) // option 2
197 char buff[len+1]; buff[len] = ’\0’; 14 ii p = {5, 5}; // option 3
198 for (int i = len-1; i >= 0; --i, x >>= 1) 15 // getting values
199 buff[i] = (char)(’0’ + (x&1)); 16 int x = p.first, y = p.second;
200 return string(buff); 17 // modifying values
201 } 18 p.first++, p.second--; // p = {6, 4}
202 19
203 /* ================== */ 20 //=======
204 /* Hexadecimal Tricks */ 21 // TUPLE
205 /* ================== */ 22 //=======
206 // get string hex representation of an integer 23 // Example: tuples of 3 ints
207 string to_hex(int num) { 24 typedef tuple<int,int,int> iii; // use iii as abbreviation
208 static char buff[100]; 25 // initialization
209 static const char* hexdigits = "0123456789abcdef"; 26 iii t(5,5,5); // option 1
210 buff[99] = ’\0’; 27 iii t = make_tuple(5,5,5); // option 2
211 int i = 98; 28 iii t = {5, 5, 5}; // option 3
212 do { 29 // getting values
213 buff[i--] = hexdigits[num & 0xf]; 30 int x,y,z;
214 num >>= 4; 31 x = get<0>(t), y = get<1>(t), z = get<2>(t); // option 1
215 } while (num); 32 tie(x,y,z) = t; // option 2
216 return string(buff+i+1); 33 // modifying values
217 } 34 get<0>(t)++, get<1>(t)--, get<2>(t)+=2; // t = {6, 4, 7}
218 // [’0’-’9’ ’a’-’f’] -> [0 - 15]
219 int char_to_digit(char c) { 3.1.2 Array
220 if (’0’ <= c && c <= ’9’)
221 return c - ’0’; 1 //================
222 return 10 + c - ’a’; 2 // declare arrays
223 } 3 //================
224 4 int arr[10];
225 /* ================= */ 5 int arr[10][10];
226 /* CLIMITS CONSTANTS */ 6 int arr[5] = {1, 2, 3, 4, 5};
227 /* ================= */ 7 int arr[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}};
228 INT_MIN INT_MAX UINT_MAX LONG_MIN LONG_MAX ULONG_MAX LLONG_MIN LLONG_MAX ULLONG_MAX 8
9 //============================
3 Data Structures 10
11
// fill array using std::fill
//============================
12 // http://www.cplusplus.com/reference/algorithm/fill/
3.1 C++ STL 13
14 // 1) arrays 1D
3.1.1 Pairs & Tuples 15 int arr[100];
16 fill(arr, arr+4, -5);
1 // references: 17 fill(arr, arr+N, val);
2 // https://www.geeksforgeeks.org/returning-multiple-values-from-a-function-using-tuple- 18 fill(arr + offset, arr + N, val);
and-pair-in-c/ 19 double arr[100];
3 // http://www.cplusplus.com/reference/utility/pair/ 20 fill(arr, arr+7, 0.999);
4 // http://www.cplusplus.com/reference/tuple/ 21
5 22 // 2) arrays 2D or more
6 //====== 23 int arr[100][100];
7 // PAIR 24 fill(&arr[0][0], &arr[0][0] + sizeof(arr), -1231);
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 5 de 40
25 28
26 //========================= 29 vector<int> v; // v = {}, v.size() == 0
27 // fill array using memset 30 v.reserve(1000); // reserve 1000 x sizeof(int) bytes of contiguous memory in advance
28 //========================= 31 // ** we use v.reserve(MAXN) when we when we know the maximum memory we will ever
29 int arr[100][100]; 32 // need to prevent unnecessary memory reallocations
30 memset(arr, -1, sizeof(arr)); 33
31 memset(arr, 0, sizeof(arr)); 34 rep(i, 1, 10) v.push_back(i); // v = { 1, 2, 3, ..., 10 }, v.size() == 10
32 // ** only works with 0 and -1 for arryas of ints/longs 35 int x = v.front(); // x = 1
33 // because memset works on bytes (same value is written on each char) 36 int y = v.back(); // y = 10
34 // sizeof(arr) returns the number of bytes in arr 37 v.pop_back(); // remove last element -> v = { 1, 2, 3, ..., 9 }, v.size() == 9
35 38
36 // in the case of char arrays, we can set any value, since 39 // clearing
37 // sizeof(char) = 1 (each char uses a single byte) 40 v.clear(); // v = {}, v.size() == 0
38 char char_arr[100][100]; 41
39 memset(char_arr, ’k’, sizeof(char_arr)); 42 //========
40 43 // RESIZE
41 // filling with -1/0 the first N ints in arr 44 //========
42 int arr[MAXN]; 45 rep(i,1,10) v.push_back(i); // v = { 1, 2, ..., 10 }
43 memset(arr, -1, sizeof(int) * N); 46 v.resize(5); // v = { 1, 2, 3, 4, 5 }
44 memset(arr, 0, sizeof(int) * N); 47 v.resize(8,100); // v = { 1, 2, 3, 4, 5, 100, 100, 100 }
45 48 v.resize(12); // v = { 1, 2, 3, 4, 5, 100, 100, 100, 0, 0, 0, 0 }
46 // interesting links: 49
47 // https://stackoverflow.com/questions/936687/how-do-i-declare-a-2d-array-in-c-using-new/ 50 //========
48 // https://stackoverflow.com/questions/8767166/passing-a-2d-array-to-a-c-function 51 // ASSIGN
52 //========
3.1.3 Vector 53 v.assign(N, 4); // v = { 4, 4, ..., 4 } (N times)
54

1 // references: 55 vector<int> v2;


2 // http://www.cplusplus.com/reference/vector/vector/ 56 v2.assign(v.begin(), v.end()); // v2 = v
3 // https://www.geeksforgeeks.org/vector-in-cpp-stl/ 57 v2.assign(v.begin() + 1, v.end() - 1); // v2 = v[1:-1]
4 #include <bits/stdc++.h> 58

5 #define rep(i,a,b) for(int i=a; i<=b; i++) 59 int arr[5] = {1, 2, 3, 4, 5};
6 using namespace std; 60 v2.assign(arr, arr + 5); // v2 = {1, 2, 3, 4, 5}
7 61 v2.assign(arr, arr + 3); // v2 = {1, 2, 3}
8 //============================== 62

9 // DECLARATION & INITIALIZATION 63 //===========================


10 //============================== 64 // EMPLACE_BACK VS PUSH_BACK
11 65 //===========================
12 // vector of ints 66 struct CustomData {
13 vector<int> v; // empty 67 int x; double y; string z;
14 vector<int> v(100); // size 100 68 CustomData(int x, double y, string z) : x(x), y(y), z(z) {}
15 vector<int> v(N); // size N, make sure N is defined 69 };
16 vector<int> v(N, 2); // size N filled with 2’s 70 vector<CustomData> v;
17 vector<int> v = { 1, 2, 3, 5, 6 }; // list initialization (since C++11) 71 // option 1: with push_back() -> object is created and then copied
18 v[0] = -8; // v = { -8, 2, 3, 5, 6 } 72 v.push_back(CustomData(1,2.32,"foo")); // using constructor
19 v[1] = 0; // v = { -8, 0, 3, 5, 6 } 73 v.push_back({1, 2.32,"bar"}); // c++11: using curly braces
20 74 // option 2: with emplace_back() -> object is created in its final location ;)
21 // vector of vector of ints 75 v.emplace_back(1, 2.32, "foo");
22 // a matrix of R rows by C columns filled with -1 76 // ** NOTE: for emplace_back() make sure your custom struct/class has a constructor
23 vector<vector<int>> matrix(R, vector<int>(C,-1)); 77 // for push_back(), no need to define a constructor
24 78

25 //===================================================== 79

26 // MODIFYING A VECTOR (capacity, size, adding elements) 80 //========================


27 ///===================================================== 81 // ITERATING OVER VECTORS
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 6 de 40
82 //======================== 14 while (!q.empty()) {
83 // reference: 15 cout << q.front() << ’ ’;
84 // https://stackoverflow.com/questions/15176104/c11-range-based-loop-get-item-by-value-or 16 q.pop();
-reference-to-const 17 } // output: 1 2 3 4 5
85 18
86 // 1) foward direction 19 //===== STACK =====
87 20 stack<int> s;
88 vector<CustomData> v(100); // vector of custom type 21 // adding to stack
89 // option 1: iterate over element copies (slower) 22 rep(i,1,5) s.push(i); // s = {1, 2, 3, 4, 5}
90 for (auto x : v) { /* do something */ } 23 // OR
91 // option 2: iterate over references (faster) 24 rep(i,1,5) s.emplace(i); // s = {1, 2, 3, 4, 5}
92 for (auto& x : v) { /* do something */ } 25 // removing from stack
93 // option 3: iterate over const references (equally fast) 26 while (!s.empty()) {
94 // * the const keyword is just to prevent unintended modifications 27 cout << s.top() << ’ ’;
95 for (const auto& x : v) { /* do something */ } 28 s.pop();
96 29 } // output: 5 4 3 2 1
97 vector<int> v {1, 2, 3, 4, 5, 6}; // vector of ints
98 for (int x : v) { /* do something */ } 3.1.5 Priority Queue
99 for (int& x : v) { /* do something */ }
100 for (const int& x : v) { /* do something */ } 1 // references:
101 2 // http://www.cplusplus.com/reference/queue/priority_queue/
102 // using iterators 3 // https://www.geeksforgeeks.org/priority-queue-in-cpp-stl/
103 for (auto it = v.begin(); it != v.end(); ++it) { 4
104 const auto& x = *it; // use *it to access original element pointed by it 5 //====================
105 /* do something with x */ 6 // 1) MAXHEAP of ints
106 } 7 //====================
107 8 priority_queue<int> q;
108 // 2) backward direction 9 q.push(30);
109 for (auto it = v.rbegin(); it != v.rend(); ++it) { 10 q.push(100);
110 const auto& x = *it; 11 q.push(25);
111 } 12 q.push(40);
112 13 cout << "Popping out elements...";
113 //==================== 14 while (!q.empty()) {
114 // SWAPPING 2 VECTORS 15 cout << ’ ’ << q.top();
115 //==================== 16 q.pop();
116 vector<int> v1 = {1, 1, 1, 1}; 17 }
117 vector<int> v2 = {2, 2, 2}; 18 cout << ’\n’;
118 v1.swap(v2); // v1 = {2, 2, 2}, v2 = {1, 1, 1, 1} 19 // Popping out elements... 100 40 30 25
20
3.1.4 Queue & Stack 21 //====================
22 // 2) MINHEAP of ints
1 // references: 23 //====================
2 // http://www.cplusplus.com/reference/queue/queue/ 24 priority_queue<int, vector<int>, greater<int>> q;
3 // https://www.geeksforgeeks.org/queue-cpp-stl/ 25 q.push(30);
4 // http://www.cplusplus.com/reference/stack/stack/ 26 q.push(100);
5 // https://www.geeksforgeeks.org/stack-in-cpp-stl/ 27 q.push(25);
6 28 q.push(40);
7 //===== QUEUE ===== 29 cout << "Popping out elements...";
8 queue<int> q; 30 while (!q.empty()) {
9 // adding to queue 31 cout << ’ ’ << q.top();
10 rep(i,1,5) q.push(i); // q = {1, 2, 3, 4, 5} 32 q.pop();
11 // OR 33 }
12 rep(i,1,5) q.emplace(i); // q = {1, 2, 3, 4, 5} 34 cout << ’\n’;
13 // removing from queue 35 // Popping out elements... 25 30 40 100
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 7 de 40
36 2 // http://www.cplusplus.com/reference/set/set/
37 //==================================== 3 // http://www.cplusplus.com/reference/set/multiset/
38 // 3) custom data + custom comparator 4 #define rep(i,a,b) for(int i=a; i<=b; i++)
39 //==================================== 5
40 6 //================
41 // option 1: overload operator< inside your struct/class 7 // INITIALIZATION
42 struct Event { 8 //================
43 double time; string name; 9 // set
44 Event (double t, string n) : time(t), name(n) {} 10 set<int> s{1, 2, 3, 4, 4, 5, 5, 5, 2, 2, 2};
45 bool overload<(const Event& rhs) const { 11 for (int x : s) cout << x; // 12345
46 // define your < operator however you want 12 // multiset
47 return time > rhs.time; 13 multiset<int> ms{1, 2, 3, 4, 4, 5, 5, 5, 2, 2, 2};
48 } 14 for (int x : s) cout << x; // 12222344555
49 }; 15
50 priority_queue<Event> q; 16 //========
51 17 // INSERT
52 // option 2: use a functor 18 //========
53 struct Event { 19 // set
54 double time; string name; 20 set<int> s;
55 Event (double t, string n) : time(t), name(n) {} 21 rep(i,1,5) s.insert(i*10); // 10 20 30 40 50
56 }; 22 auto ret = s.insert(20); // no new element inserted
57 struct EventCmp { 23 auto it = ret.first;
58 bool operator()(const Event& lhs, const Event& rhs) { 24 if (it.second) cout << "20 inserted for the first time\n";
59 return lhs.time > rhs.time; 25 else cout << "20 already in set\n";
60 } 26 int myints[]= {5,10,15}; // 10 already in set, not inserted
61 }; 27 s.insert(myints,myints+3);
62 priority_queue<Event, vector<Event>, EventCmp> q; 28 cout << "s contains:";
63 29 for (int x : s) cout << ’ ’ << x;
64 // option 3: use a lambda function 30 cout << ’\n’; // 5 10 15 20 30 40 50
65 struct Event { 31 // multiset
66 double time; string name; 32 // ** same as set, but allows duplicates, so insert returns an iterator
67 Event (double t, string n) : time(t), name(n) {} 33 // not a pair
68 }; 34
69 auto cmp = [](const Event& lhs const Event& rhs) { 35 //=======
70 return lhs.time > rhs.time; 36 // ERASE
71 } 37 //=======
72 priority_queue<Event, vector<Event>, decltype(cmp)> q(cmp); 38 // -- set
73 39 set<int> s;
74 // usage example 40 rep(i,1,9) s.insert(i*10); // 10 20 30 40 50 60 70 80 90
75 q.emplace(10.2, "Peter"); 41 auto it = s.begin();
76 q.emplace(2.7, "Mary"); 42 ++it; // "it" points now to 20
77 q.emplace(5.3, "John"); 43 s.erase(it); // erase by pointer
78 q.emplace(0.3, "Bob"); 44 s.erase(40); // erase by value
79 cout << "Events:"; 45 it = s.find(60); // iterator pointing to 60
80 while (!q.empty()) { 46 s.erase(it, s.end()); // erase everything in range [it, s.end())
81 Event& e = q.top(); 47 // s = 10 30 50
82 cout << " (" << e.time << ’,’ << e.name << ")"; 48 // -- multiset
83 q.pop(); 49 multiset<int> ms;
84 } 50 ms.insert (40); // 40
85 // Events: (0.3,Bob) (2.7,Mary) (5.3,John) (10.2,Peter) 51 rep(i,1,6) ms.insert(i*10); // 10 20 30 40 40 50 60
52 auto it=ms.begin();
3.1.6 Set & Multiset 53 it++; // ^
54 ms.erase(it); // 10 30 40 40 50 60
1 // references: 55 ms.erase(40); // 10 30 50 60
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 8 de 40
56 it=ms.find(50); 110 //=============================
57 ms.erase(it, ms.end()); // 10 30 111 // SET/MULTISET of Custom Data
58 112 //=============================
59 //======= 113 struct CustomData {
60 // FIND 114 int x; string name;
61 //======= 115 CustomData(int x, string n) : x(x), name(n) {}
62 // -- set 116 // define operator <
63 set<int> s; 117 bool operator<(const CustomData& rhs) const {
64 rep(i,1,5) s.insert(i*10); // 10 20 30 40 50 118 return x < rhs.x;
65 auto it=s.find(20); 119 }
66 s.erase(it); // 10 30 40 50 120 };
67 s.erase(s.find(40)); // 10 30 50 121 set<CustomData> s;
68 // -- multiset 122 multiset<CustomData> ms;
69 // ** same as set 123 s.emplace(1, "foo");
70 124 s.emplace(2, "bar");
71 //=============================== 125 ms.emplace(-12, "bla");
72 // lower_bound() & upper_bound()
73 //=============================== 3.1.7 Map & Multimap
74 // -- set
75 set<int> s; 1 // references:
76 rep(i,1,9) s.insert(i*10); // 10 20 30 40 50 60 70 80 90 2 // http://www.cplusplus.com/reference/map/map/
77 auto itlow=s.lower_bound(30); // ^ 3 // http://www.cplusplus.com/reference/map/multimap/
78 auto itup=s.upper_bound(60); // ^ 4 // ** SUMMARY **
79 s.erase(itlow,itup); // 10 20 70 80 90 5 // same as set and multiset, except that for each key
80 // -- multiset 6 // now there is a value associated to it (if we only consider
81 multiset<int> ms{30, 10, 10, 40, 30, 90}; // 10 10 30 30 40 90 7 // the keys is the same as set/multiset)
82 auto itlow = ms.lower_bound(30); // ^ 8
83 auto itup = ms.upper_bound(40); // ^ 9 //================
84 ms.erase(itlow,itup); // 10 20 90 10 // INITIALIZATION
85 11 //================
86 //======================= 12 // --- map
87 // multiset::equal_range 13 map<string,float> m {{"a",1.50}, {"b",2.10}, {"c",1.40}};
88 //======================= 14 // or
89 int myints[] = {77,30,16,2,30,30}; 15 map<string,float> m;
90 multiset<int> ms(myints, myints+6); // 2 16 30 30 30 77 16 m.emplace("a", 1.50);
91 auto ret = ms.equal_range(30); // ^ ^ 17 m.emplace("b", 2.10);
92 // ret.first -> first 30 (same as ms.lower_bound(30)) 18 m.emplace("c", 1.40);
93 // ret.second -> 77 (same as ms.upper_bound(30)) 19 // --- multimap
94 ms.erase(ret.first, ret.second); // 2 16 77 20 // ** same as map
95 21
96 //======= 22 //=========
97 // COUNT 23 // INSERT
98 //======= 24 //=========
99 // --- set 25 // --- map
100 set<int> s{3, 6, 9, 12}; 26 map<char,int> m;
101 rep(i,0,9) { 27 // first insert function version (single parameter):
102 cout << i; 28 m.insert( pair<char,int>(’a’,100) );
103 if (s.count(i) > 0) cout << " is an element of s.\n"; 29 m.insert( pair<char,int>(’z’,200) );
104 else cout << " is not an element of s.\n"; 30 auto ret = m.insert ( pair<char,int>(’z’,500) );
105 } 31 if (ret.second==false) {
106 // --- multiset 32 cout << "element ’z’ already existed";
107 multiset<int> ms{10,73,12,22,73,73,12}; 33 cout << " with a value of " << ret.first->second << ’\n’;
108 cout << ms.count(73); // 3 34 }
109 35 // second insert function version (with hint position):
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 9 de 40
36 auto it = m.begin(); 90 first=map<char,int>(); // and first is now empty
37 m.insert(it, pair<char,int>(’b’,300)); // max efficiency inserting 91 cout << "Size of first: " << first.size() << ’\n’;
38 m.insert(it, pair<char,int>(’c’,400)); // no max efficiency inserting 92 cout << "Size of second: " << second.size() << ’\n’;
39 // third insert function version (range insertion): 93
40 map<char,int> m2; 94 //=========================
41 m2.insert(m.begin(), m.find(’c’)); 95 // generating ids with map
42 // showing contents: 96 //=========================
43 cout << "m contains:\n"; 97 int get_id(string& name) {
44 for (auto& kv : m) cout << kv.first << " => " << kv.second << ’\n’; 98 static int id = 0;
45 cout << "m2 contains:\n"; 99 static map<string,int> name2id;
46 for (auto& kv : m2) cout << kv.first << " => " << kv.second << ’\n’; 100 auto it = name2id.find(name);
47 /* 101 if (it == name2id.end())
48 element ’z’ already existed with a value of 200 102 return name2id[name] = id++;
49 m contains: 103 return it->second;
50 a => 100 104 }
51 b => 300
52 c => 400 3.1.8 Unordered Set & Multiset
53 z => 200
54 m2 contains: 1 // references:
55 a => 100 2 // http://www.cplusplus.com/reference/unordered_set/unordered_set/
56 b => 300 3 // http://www.cplusplus.com/reference/unordered_set/unordered_multiset/
57 */ 4 // ** unordered_multiset is basically the same as unordered_set
58 // --- multimap 5 // except that unordered_multiset allows duplicate elements
59 // ** same as map 6
60 7 //=========
61 //================= 8 // RESERVE
62 // map::operator[] 9 //=========
63 //================= 10 unordered_set<string> s;
64 map<char,string> m; 11 s.reserve(5);
65 m[’a’]="an element"; 12 s.insert("office");
66 m[’b’]="another element"; 13 s.insert("house");
67 m[’c’]=m[’b’]; 14 s.insert("gym");
68 cout << "m[’a’] is " << m[’a’] << ’\n’; 15 s.insert("parking");
69 cout << "m[’b’] is " << m[’b’] << ’\n’; 16 s.insert("highway");
70 cout << "m[’c’] is " << m[’c’] << ’\n’; 17 cout << "s contains:";
71 cout << "m[’d’] is " << m[’d’] << ’\n’; // (’d’ -> "") is created by default 18 for (const string& x: s) cout << " " << x;
72 cout << "m now contains " << m.size() << " elements.\n"; 19 cout << ’\n’; // s contains: highway house office gym parking
73 /* 20 // By calling reserve with the size we expected for the unordered_set
74 m[’a’] is an element 21 // container we avoided the multiple rehashes that the increases in container
75 m[’b’] is another element 22 // size could have produced and optimized the size of the hash table.
76 m[’c’] is another element 23
77 m[’d’] is 24 //========
78 m now contains 4 elements. 25 // INSERT
79 */ 26 //========
80 27 unordered_set<string> s = {"yellow","green","blue"};
81 //================= 28 array<string,2> arr = {"black","white"};
82 // map::operator= 29 string mystring = "red";
83 //================= 30 s.insert(mystring); // copy insertion
84 map<char,int> first; 31 s.insert(mystring+"dish"); // move insertion
85 map<char,int> second; 32 s.insert(arr.begin(), arr.end()); // range insertion
86 first[’x’]=8; 33 s.insert( {"purple","orange"} ); // initializer list insertion
87 first[’y’]=16; 34 cout << "s contains:";
88 first[’z’]=32; 35 for (const string& x: s) cout << " " << x;
89 second=first; // second now contains 3 ints 36 cout << ’\n’;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 10 de 40
37 //s contains: green blue reddish white yellow black red orange purple 18 m.emplace("c", 1.40);
38 19 // --- unordered_multimap
39 //======= 20 // ** same as unordered_map
40 // ERASE 21
41 //======= 22 //=========
42 unordered_set<string> s = 23 // INSERT
43 {"USA","Canada","France","UK","Japan","Germany","Italy"}; 24 //=========
44 s.erase( s.begin() ); // erasing by iterator 25 // --- unordered_map
45 s.erase( "France" ); // erasing by key 26 unordered_map<string,double>
46 s.erase( s.find("Japan"), s.end() ); // erasing by range 27 myrecipe,
47 cout << "s contains:"; 28 mypantry = {{"milk",2.0},{"flour",1.5}};
48 for ( const string& x: s ) cout << " " << x; 29 pair<string,double> myshopping("baking powder",0.3);
49 cout << ’\n’; // s contains: Canada USA Italy 30 myrecipe.insert(myshopping); // copy insertion
50 31 myrecipe.insert(make_pair("eggs",6.0)); // move insertion
51 //====== 32 myrecipe.insert(mypantry.begin(), mypantry.end()); // range insertion
52 // FIND 33 myrecipe.insert( {{"sugar",0.8},{"salt",0.1}} ); // initializer list insertion
53 //====== 34 cout << "myrecipe contains:" << ’\n’;
54 unordered_set<string> s{"red","green","blue"}; 35 for (auto& x: myrecipe) cout << x.first << ": " << x.second << ’\n’;
55 auto it = s.find("black"); 36 cout << ’\n’;/*
56 assert (it == s.end()); 37 myrecipe contains:
57 assert (s.find("red") != s.end()); 38 salt: 0.1
58 39 eggs: 6
59 //======= 40 sugar: 0.8
60 // COUNT 41 baking powder: 0.3
61 //======= 42 flour: 1.5
62 unordered_set<string> s { "hat", "umbrella", "suit" }; 43 milk: 2 */
63 for (auto& x: {"hat","sunglasses","suit","t-shirt"}) { 44 // --- unordered_multimap
64 if (s.count(x) > 0) cout << "s has " << x << ’\n’; 45 // ** same as unordered_map
65 else cout << "s has no " << x << ’\n’; 46
66 } /* 47 //==========================
67 s has hat 48 // unordered_map::operator[]
68 s has no sunglasses 49 //===========================
69 s has suit 50 unordered_map<string,string> m;
70 s has no t-shirt */ 51 m["Bakery"]="Barbara"; // new element inserted
52 m["Seafood"]="Lisa"; // new element inserted
3.1.9 Unordered Map & Multimap 53 m["Produce"]="John"; // new element inserted
54 string name = m["Bakery"]; // existing element accessed (read)
1 // references: 55 m["Seafood"] = name; // existing element accessed (written)
2 // http://www.cplusplus.com/reference/unordered_map/unordered_map/ 56 m["Bakery"] = m["Produce"]; // existing elements accessed (read/written)
3 // http://www.cplusplus.com/reference/unordered_map/unordered_multimap/ 57 name = m["Deli"]; // non-existing element: new element "Deli" inserted!
4 // ** SUMMARY ** 58 m["Produce"] = m["Gifts"]; // new element "Gifts" inserted, "Produce" written
5 // same as unordered_set and unordered_multiset, except that for each key 59 for (auto& x: m) cout << x.first << ": " << x.second << ’\n’;
6 // now there is a value associated to it (if we only consider 60 /*
7 // the keys is the same as unordered_set/unordered_multiset) 61 Seafood: Barbara
8 62 Deli:
9 //================ 63 Bakery: John
10 // INITIALIZATION 64 Gifts:
11 //================ 65 Produce:
12 // --- unordered_map 66 */
13 unordered_map<string,float> m {{"a",1.50}, {"b",2.10}, {"c",1.40}}; 67

14 // or 68 //==========================
15 unordered_map<string,float> m; 69 // unordered_map::operator=
16 m.emplace("a", 1.50); 70 //==========================
17 m.emplace("b", 2.10); 71 typedef unordered_map<string,string> stringmap;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.1 C++ STL Página 11 de 40
72 stringmap merge (stringmap a,stringmap b) { 22 // 1 10 20 30 30 20 2 3 4 5
73 stringmap temp(a); temp.insert(b.begin(),b.end()); return temp; 23 // ^
74 } 24 cout << "mylist contains:";
75 int main() { 25 for (int x : mylist) cout << ’ ’ << x;
76 stringmap first, second, third; 26 cout << ’\n’;
77 first = {{"AAPL","Apple"},{"MSFT","Microsoft"}}; // init list 27 // mylist contains: 1 10 20 30 30 20 2 3 4 5
78 second = {{"GOOG","Google"},{"ORCL","Oracle"}}; // init list 28
79 third = merge(first,second); // move 29 //=======
80 first = third; // copy 30 // ERASE
81 cout << "first contains:"; 31 //=======
82 for (auto& x: first) cout << " " << x.first << ":" << x.second; 32 // http://www.cplusplus.com/reference/list/list/erase/
83 cout << ’\n’; 33
84 return 0; 34 list<int> mylist;
85 } 35 list<int>::iterator it1,it2;
86 // first contains: MSFT:Microsoft AAPL:Apple GOOG:Google ORCL:Oracle 36 // set some values:
37 rep(i,1,9) mylist.push_back(i*10);
3.1.10 Deque 38 // 10 20 30 40 50 60 70 80 90
39 it1 = it2 = mylist.begin(); // ^^
1 // references: 40 advance (it2,6); // ^ ^
2 // http://www.cplusplus.com/reference/deque/deque/ 41 ++it1; // ^ ^
3 // https://www.geeksforgeeks.org/deque-cpp-stl/ 42

4 // SUMMARY: deque can do the same things as vector 43 it1 = mylist.erase(it1); // 10 30 40 50 60 70 80 90


5 // + push_front() + emplace_front() 44 // ^ ^
6 // - contiguous memory allocation is not guaranteed 45

7 // (elements may be stored in fragmented chunks of memory) 46 it2 = mylist.erase(it2); // 10 30 40 50 60 80 90


8 deque<int> dq = { 1, 2, 3 }; 47 // ^ ^
9 dq.push_back(8); // { 1, 2, 3, 8 } 48 ++it1; // ^ ^
10 dq.push_front(100); // { 100, 1, 2, 3, 8 } 49 --it2; // ^ ^
11 dq.pop_back(); // { 100, 1, 2, 3 } 50 mylist.erase(it1,it2); // 10 30 60 80 90
12 dq.pop_front(); // { 1, 2, 3} 51 // ^
52 cout << "mylist contains:";
3.1.11 List 53 for (int x : mylist) cout << ’ ’ << x;
54 cout << ’\n’;
1 // full documentation: 55 // mylist contains: 10 30 60 80 90
2 // http://www.cplusplus.com/reference/list/list/
3 // https://www.geeksforgeeks.org/list-cpp-stl/ 3.1.12 Policy based Data Structures: Ordered Set
4
5 //======== 1 // references:
6 // INSERT 2 // https://www.geeksforgeeks.org/ordered-set-gnu-c-pbds/
7 //======== 3 // https://www.geeksforgeeks.org/policy-based-data-structures-g/
8 // http://www.cplusplus.com/reference/list/list/insert/ 4 // https://codeforces.com/blog/entry/11080
9 5 #include <bits/stdc++.h>
10 list<int> mylist; 6 using namespace std;
11 list<int>::iterator it; 7 #include <ext/pb_ds/assoc_container.hpp>
12 // set some initial values: 8 #include <ext/pb_ds/tree_policy.hpp>
13 rep(i,1,5) mylist.push_back(i); // 1 2 3 4 5 9 using namespace __gnu_pbds;
14 it = mylist.begin(); 10
15 ++it; // it points now to number 2 ^ 11 typedef tree<
16 mylist.insert(it,10); // 1 10 2 3 4 5 12 int,
17 // "it" still points to number 2 ^ 13 null_type,
18 mylist.insert (it,2,20); // 1 10 20 20 2 3 4 5 14 less<int>,
19 --it; // it points now to the second 20 ^ 15 rb_tree_tag,
20 vector<int> myvector (2,30); 16 tree_order_statistics_node_update
21 mylist.insert (it,myvector.begin(),myvector.end()); 17 > ordered_set;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.2 Sparse Tables Página 12 de 40
18 14 n = arr->size();
19 int main() { 15 int maxlog = 31 - __builtin_clz(n);
20 ordered_set o_set; 16 memo.assign(n * (maxlog + 1), -1);
21 o_set.insert(5); 17 }
22 o_set.insert(1); 18 // dp(i,e) = min { arr[j] } for j in {i, i+1, ..., i+2^e-1}
23 o_set.insert(2); 19 int dp(int i, int e) {
24 // Finding the second smallest element 20 int& ans = memo[e * n + i];
25 // in the set using * because 21 if (ans != -1) return ans;
26 // find_by_order returns an iterator 22 if (e == 0) return ans = (*arr)[i];
27 cout << *(o_set.find_by_order(1)) << ’\n’; 23 return ans = min(dp(i, e-1), dp(i+(1<<(e-1)), e-1));
28 // Finding the number of elements 24 }
29 // strictly less than k=4 25
30 cout << o_set.order_of_key(4) << ’\n’; 26 // ---- RMQ = Range Minimun Query ----
31 // Finding the count of elements less 27 // rmq(l,r) = min { arr[j] } for j in {l, l+1, ..., r}
32 // than or equal to 4 i.e. striclty less 28
33 // than 5 if integers are present 29 // option 1: complexity O(1)
34 cout << o_set.order_of_key(5) << ’\n’; 30 int rmq_O1(int l, int r) {
35 // Deleting 2 from the set if it exists 31 int e = 31 - __builtin_clz(r - l + 1);
36 if (o_set.find(2) != o_set.end()) 32 return min(dp(l,e), dp(r - (1 << e) + 1, e));
37 o_set.erase(o_set.find(2)); 33 }
38 // Now after deleting 2 from the set 34
39 // Finding the second smallest element in the set 35 // option 2: complexity O(log N)
40 cout << *(o_set.find_by_order(1)) << ’\n’; 36 int rmq_Ologn(int l, int r) {
41 // Finding the number of 37 int ans = INT_MAX;
42 // elements strictly less than k=4 38 int d = r-l+1;
43 cout << o_set.order_of_key(4) << ’\n’; 39 for (int e = 0; d; e++, d>>=1) {
44 return 0; 40 if (d & 1) {
45 } 41 ans = min(ans, dp(l, e));
42 l += 1 << e;
3.1.13 Bitset 43 }
44 }
1 bitset<4> foo; // 0000 45 return ans;
2 foo.size(); // 4 46 }
3 foo.set(); // 1111 47 };
4 foo.set(1,0); // 1011 48
5 foo.test(1); // false 49 // example of usage
6 foo.set(1); // 1111 50 int main() {
7 foo.test(1); // true 51 vector<int> arr = {1, 3, 4, 3, 1, 6, 7, 4, 8, 9};
52 SparseTable st(arr);
3.2 Sparse Tables 53 while (true) {
54 int l, r; cin >> l >> r; // read query
1 #include <bits/stdc++.h> 55 cout << st.rmq_O1(l,r) << ’\n’; // print minimum
2 using namespace std; 56 }
3 57 return 0;
4 // time complexity: 58 }
5 // - filling DP table: O(N log N)
6 // - answering queries: O(1) / O(log N) 3.3 Fenwick Tree
7
8 struct SparseTable { 1 struct BIT { // BIT = binary indexed tree (a.k.a. Fenwick Tree)
9 int n; 2 vector<int> bit;
10 vector<int> memo; 3 BIT(int n) { bit.assign(n+1, 0); }
11 vector<int>* arr; 4 // prefix sum query (sum in range 1 .. k)
12 SparseTable(vector<int>& _arr) { 5 int psq(int k) {
13 arr = &_arr; 6 int sum = 0;
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.4 Fenwick Tree 2D Página 13 de 40
7 for (; k; k -= (k & -k)) sum += bit[k]; 4 //=============================
8 return sum; 5 // 1) Segment Tree - ITERATIVE
9 } 6 //=============================
10 // range sum query (sum in range a .. b) 7 // source: https://docs.google.com/document/d/1rcex_saP4tExbbU62qGUjR3eenxOh-50
11 int rsq(int a, int b) { i9Y45WtHkc4/
12 return psq(b) - psq(a-1); 8 /*
13 } 9 Se requiere un struct para el nodo (ej: prodsgn).
14 // increment k’th value by v (and propagate) 10 Un nodo debe tener tres constructores:
15 void add(int k, int v) { 11 Aridad 0: Construye el neutro de la operacion
16 for (; k < bit.size(); k += (k & -k)) bit[k] += v; 12 Aridad 1: Construye un nodo hoja a partir del input
17 } 13 Aridad 2: Construye un nodo segun sus dos hijos
18 }; 14
15 Construccion del segment tree:
3.4 Fenwick Tree 2D 16 Hacer un arreglo de nodos (usar ctor de aridad 1).
17 ST<miStructNodo> miSegmentTree(arregloDeNodos);
18 Update:
1 struct BIT2D { // BIT = binary indexed tree (a.k.a. Fenwick Tree) 19 miSegmentTree.set_point(indice, miStructNodo(input));
2 vector<int> bit; 20 Query:
3 int R, C; 21 miSegmentTree.query(l, r) es inclusivo exclusivo y da un nodo. Usar la info del nodo
4 BIT2D(int _R, int _C) : R(_R+1), C(_C+1) { para obtener la respuesta.
5 bit.assign(R*C, 0); 22 */
6 } 23 template<class node> struct ST {
7 void add(int r, int c, int value) { 24 vector<node> t; int n;
8 for (int i = r; i < R; i += (i&-i)) 25 ST(vector<node> &arr) {
9 for (int j = c; j < C; j += (j&-j)) 26 n = arr.size();
10 bit[i * C + j] += value; 27 t.resize(n*2);
11 } 28 copy(arr.begin(), arr.end(), t.begin() + n);
12 // sum[(1, 1), (r, c)] 29 for (int i = n-1; i > 0; --i)
13 int sum(int r, int c) { 30 t[i] = node(t[i<<1], t[i<<1|1]);
14 int res = 0; 31 }
15 for (int i = r; i; i -= (i&-i)) 32 // 0-indexed
16 for (int j = c; j; j -= (j&-j)) 33 void set_point(int p, const node &value) {
17 res += bit[i * C + j]; 34 for (t[p += n] = value; p > 1; p >>= 1)
18 return res; 35 t[p>>1] = node(t[p], t[p^1]);
19 } 36 }
20 // sum[(r1, c1), (r2, c2)] 37 // inclusive exclusive, 0-indexed
21 int sum(int r1, int c1, int r2, int c2) { 38 node query(int l, int r) {
22 return sum(r2, c2) - sum(r1-1, c2) - sum(r2, c1-1) + sum(r1-1, c1-1); 39 node ansl, ansr;
23 } 40 for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
24 // get value at cell (r,c) 41 if (l&1) ansl = node(ansl, t[l++]);
25 int get(int r, int c) { 42 if (r&1) ansr = node(t[--r], ansr);
26 return sum(r, c, r, c); 43 }
27 } 44 return node(ansl, ansr);
28 // set value to cell (r,c) 45 }
29 int set(int r, int c, int value) { 46 };
30 add(r, c, -get(r, c) + value); 47
31 } 48 // Interval Product (LiveArchive)
32 }; 49 struct prodsgn {
50 int sgn;
3.5 Segment Tree 51 prodsgn() {sgn = 1;}
52 prodsgn(int x) { sgn = (x > 0) - (x < 0); }
1 #include <bits/stdc++.h> 53 prodsgn(const prodsgn &a, const prodsgn &b) { sgn = a.sgn*b.sgn; }
2 using namespace std; 54 };
3 55
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.6 Segment Tree Lazy Página 14 de 40
56 // Maximum Sum (SPOJ) 110 if (j < a or a < i) return;
57 struct maxsum { 111 if (i == j) st[a] += value;
58 int first, second; 112 else {
59 maxsum() {first = second = -1;} 113 int m = (i+j)/2, l = u*2+1, r = u*2+2;
60 maxsum(int x) { first = x; second = -1; } 114 update(a, value, l, i, m);
61 maxsum(const maxsum &a, const maxsum &b) { 115 update(a, value, r, m+1, j);
62 if (a.first > b.first) { 116 st[u] = t::merge_op(st[l], st[r]);
63 first = a.first; 117 }
64 second = max(a.second, b.first); 118 }
65 } else { 119
66 first = b.first; second = max(a.first, b.second); 120 public:
67 } 121 ST(vector<ll>& v) {
68 } 122 arr = &v;
69 int answer() { return first + second; } 123 n = v.size();
70 }; 124 st.resize(n*4+5);
71 125 build(0, 0, n-1);
72 // Range Minimum Query 126 }
73 struct rminq { 127
74 int value; 128 ll query(int a, int b) {
75 rminq() {value = INT_MAX;} 129 return query(a, b, 0, 0, n-1);
76 rminq(int x) {value = x;} 130 }
77 rminq(const rminq &a, const rminq &b) { 131
78 value = min(a.value, b.value); 132 void update(int a, ll value) {
79 } 133 update(a, value, 0, 0, n-1);
80 }; 134 }
81 135 };
82 //============================= 136
83 // 2) Segment Tree - RECURSIVE 137 struct RSQ { // range sum query
84 //============================= 138 static ll const neutro = 0;
85 139 static ll merge_op(ll x, ll y) { return x + y; }
86 template<class t> class ST { 140 };
87 vector<ll> *arr, st; int n; 141
88 142 struct RMinQ { // range minimun query
89 void build(int u, int i, int j) { 143 static ll const neutro = LLONG_MAX;
90 if (i == j) { 144 static ll merge_op(ll x, ll y) { return min(x, y); }
91 st[u] = (*arr)[i]; 145 };
92 return; 146
93 } 147 struct RMaxQ { // range maximum query
94 int m = (i+j)/2, l = u*2+1, r = u*2+2; 148 static ll const neutro = LLONG_MIN;
95 build(l, i, m); 149 static ll merge_op(ll x, ll y) { return max(x, y); }
96 build(r, m+1, j); 150 };
97 st[u] = t::merge_op(st[l], st[r]); 151
98 } 152 // usage
99 153 int main() {
100 ll query(int a, int b, int u, int i, int j) { 154 vector<int> A = { 18, 17, 13, 19, 15, 11, 20 };
101 if (j < a or b < i) return t::neutro; 155 ST<RSQ> stl(A);
102 if (a <= i and j <= b) return st[u]; 156 stl.update(2, 100);
103 int m = (i+j)/2, l = u*2+1, r = u*2+2; 157 stl.query(1, 3);
104 ll x = query(a, b, l, i, m); 158 return 0;
105 ll y = query(a, b, r, m+1, j); 159 }
106 return t::merge_op(x, y);
107 } 3.6 Segment Tree Lazy
108
109 void update(int a, ll value, int u, int i, int j) { 1 #include <bits/stdc++.h>
Pablo Messina’s ICPC Notebook 3 DATA STRUCTURES - 3.7 Union-Find Página 15 de 40
2 using namespace std; 56 }
3 typedef long long int ll; 57
4 58 SegTreeLazy(int64_t n) {
5 template<class t> class SegTreeLazy { 59 arr = new vector<ll>(4 * n);
6 vector<ll> *arr, st, lazy; int n; 60 this->n = n;
7 61 st.resize(n*4+5);
8 void build(int u, int i, int j) { 62 lazy.assign(n*4+5, 0);
9 if (i == j) { 63 build(0, 0, n-1);
10 st[u] = (*arr)[i]; 64 }
11 return; 65
12 } 66 ll query(int a, int b) {
13 int m = (i+j)/2, l = u*2+1, r = u*2+2; 67 return query(a, b, 0, 0, n-1);
14 build(l, i, m); 68 }
15 build(r, m+1, j); 69
16 st[u] = t::merge_op(st[l], st[r]); 70 void update(int a, int b, ll value) {
17 } 71 update(a, b, value, 0, 0, n-1);
18 72 }
19 void propagate(int u, int i, int j, ll x) { 73 };
20 st[u] = t::range_op(st[u], i, j, x); 74
21 if (i != j) { 75 struct RSQ { // range sum query
22 lazy[u*2+1] = t::prop_left_op(lazy[u*2+1], x); 76 static ll const neutro = 0;
23 lazy[u*2+2] = t::prop_right_op(lazy[u*2+2], x); 77 static ll merge_op(ll x, ll y) { return x + y; }
24 } 78 static ll range_op(ll st_u, int i, int j, ll x) { return st_u + (j - i + 1) * x; }
25 lazy[u] = 0; 79 static ll prop_left_op(ll left_child, ll x) { return left_child + x; }
26 } 80 static ll prop_right_op(ll right_child, ll x) { return right_child + x; }
27 81 };
28 ll query(int a, int b, int u, int i, int j) { 82
29 if (j < a or b < i) return t::neutro; 83 struct RMinQ { // range minimum query
30 if (lazy[u]) propagate(u, i, j, lazy[u]); 84 static ll const neutro = LLONG_MAX;
31 if (a <= i and j <= b) return st[u]; 85 static ll merge_op(ll x, ll y) { return min(x, y); }
32 int m = (i+j)/2, l = u*2+1, r = u*2+2; 86 static ll range_op(ll st_u, int a, int b, ll x) { return st_u + x; }
33 ll x = query(a, b, l, i, m); 87 static ll prop_left_op(ll left_child, ll x) { return left_child + x; }
34 ll y = query(a, b, r, m+1, j); 88 static ll prop_right_op(ll right_child, ll x) { return right_child + x; }
35 return t::merge_op(x, y); 89 };
36 } 90
37 91 struct RMaxQ { // range maximum query
38 void update(int a, int b, ll value, int u, int i, int j) { 92 static ll const neutro = LLONG_MIN;
39 if (lazy[u]) propagate(u, i, j, lazy[u]); 93 static ll merge_op(ll x, ll y) { return max(x, y); }
40 if (a <= i and j <= b) propagate(u, i, j, value); 94 static ll range_op(ll st_u, int a, int b, ll x) { return st_u + x; }
41 else if (j < a or b < i) return; else { 95 static ll prop_left_op(ll left_child, ll x) { return left_child + x; }
42 int m = (i+j)/2, l = u*2+1, r = u*2+2; 96 static ll prop_right_op(ll right_child, ll x) { return right_child + x; }
43 update(a, b, value, l, i, m); 97 };
44 update(a, b, value, r, m+1, j); 98
45 st[u] = t::merge_op(st[l], st[r]); 99 // usage
46 } 100 int main() {
47 } 101 vector<ll> A = { 18, 17, 13, 19, 15, 11, 20 };
48 102 SegTreeLazy<RSQ> stl(A);
49 public: 103 stl.update(1, 5, 100);
50 SegTreeLazy(vector<ll>& v) { 104 stl.query(1, 3);
51 arr = &v; 105 return 0;
52 n = v.size(); 106 }
53 st.resize(n*4+5);
lazy.assign(n*4+5, 0);
54
55 build(0, 0, n-1);
3.7 Union-Find
Pablo Messina’s ICPC Notebook 4 BINARY SEARCH - Página 16 de 40
1 #include <bits/stdc++.h> 23 if (a[m] >= key)
2 using namespace std; 24 j = m;
3 25 else
4 struct UnionFind { 26 i = m + 1;
5 vector<int> p, rank, setSize; 27 }
6 int numSets; 28 return i;
7 UnionFind(int n) { 29 }
8 numSets = n; setSize.assign(n, 1); rank.assign(n, 0); p.resize(n); 30
9 rep(i,0,n-1) p[i] = i; 31 // -----------------------------
10 } 32 // EXAMPLE 2: Integer Upperbound
11 int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); } 33 // predicate(a, i, key) = (a[i] > key)
12 bool isSameSet(int i, int j) { return findSet(i) == findSet(j); } 34 // i.e. "first element > key"
13 void unionSet(int i, int j) { 35 int upperbound(vector<int>& a, int key, int i, int j) {
14 if (!isSameSet(i, j)) { 36 while (i < j) {
15 numSets--; 37 int m = (i + j) / 2;
16 int x = findSet(i), y = findSet(j); 38 if (a[m] > key)
17 // rank is used to keep the tree short 39 j = m;
18 if (rank[x] > rank[y]) { 40 else
19 p[y] = x; setSize[x] += setSize[y]; 41 i = m + 1;
20 } else { 42 }
21 p[x] = y; setSize[y] += setSize[x]; 43 return i
22 if (rank[x] == rank[y]) rank[y]++; 44 }
23 } 45
24 } 46 /* ======================================= */
25 } 47 /* std::upper_bound(), std::lower_bound() */
26 int numDisjointSets() { return numSets; } 48 /* ======================================= */
27 int sizeOfSet(int i) { return setSize[findSet(i)]; } 49
28 }; 50 // search between [first, last)
51 // if no value is >= key (lb) / > key (ub), return last
4 Binary Search 52
53 #include <bits/stdc++.h>
54

1 // Find the index of the first item that satisfies a predicate 55 int main () {
2 // over a range [i,j), i.e., from i to j-1 56 vector<int> v{10,20,30,30,20,10,10,20}; // 10 20 30 30 20 10 10 20
3 // If no such index exists, j is returned 57 sort (v.begin(), v.end()); // 10 10 10 20 20 20 30 30
4 function binsearch(array, i, j) { 58 auto low = lower_bound (v.begin(), v.end(), 20); // ^
5 assert(i < j) // since the range is [i,j), then j must be > i 59 auto up = upper_bound (v.begin(), v.end(), 20); // ^
6 while (i < j) { 60 cout << "lower_bound at position " << (low- v.begin()) << ’\n’;
7 m = (i+j) >> 1; // m = (i+j) / 2; 61 cout << "upper_bound at position " << (up - v.begin()) << ’\n’;
8 if (predicate(array[m])) 62 return 0;
9 j = m 63 }
10 else 64

11 i = m + 1 65 // ------------------------------------------------
12 } 66 // Query: how many items are LESS THAN (<) value x
13 return i; // notice that i == j if the predicate is false for the whole range 67

14 } 68 lower_bound(v.begin(), v.end(), x) - v.begin();


15 69

16 // ----------------------------- 70 // ------------------------------------------------
17 // EXAMPLE 1: Integer Lowerbound 71 // Query: how many items are GREATER THAN (>) value x
18 // predicate(a, i, key) = (a[i] >= key) 72

19 // i.e. "first element >= key" 73 v.end() - upper_bound(v.begin(), v.end(), x);


20 int lowerbound(vector<int>& a, int key, int i, int j) { 74

21 while (i < j) { 75 //======================


22 int m = (i + j) / 2; 76 // std::binary_search()
Pablo Messina’s ICPC Notebook 6 DYNAMIC PROGRAMMING - Página 17 de 40
77 //====================== 17 left = m1, right = m2;
78 bool myfunction (int i,int j) { return (i<j); } 18 }
79 std::vector<int> v{1,2,3,4,5,4,3,2,1}; 19
80 sort(v.begin(), v.end()); 20 ans = (v1 + v2) * 0.5;
81 bool found = std::binary_search (v.begin(), v.end(), 6, myfunction)
82
83
6 Dynamic Programming
84 /* ======================= */
85 /* Discrete Ternary Search */ 6.1 Longest Increasing Subsequence
86 /* ======================= */
87
88 int min_search(int i, int j) { 1 // =====================================
89 while (i < j) { 2 // LIS (Longest Increasing Subsequence)
90 int m = (i+j)/2; 3 // =====================================
91 int slope = eval(m+1) - eval(m); 4 // references:
92 if (slope >= 0) 5 // https://stackoverflow.com/questions/2631726/how-to-determine-the-longest-increasing-
93 j = m; subsequence-using-dynamic-programming
94 else 6 const int MAXLEN = 1000000;
95 i = m+1; 7 // return the length of the longest increasing (non-decreasing)
96 } 8 // subsequence in values
97 return i; 9 int LIS(vector<int>& values) {
98 } 10 static int q[MAXLEN+1];
99
11 int len = 0;
100 int max_search(int i, int j) { 12 q[0] = -INT_MAX; // make sure it’s strictly smallest
101 while (i < j) { 13 for (int val : values) {
102 int m = (i+j)/2; 14 if (q[len] < val) { // use <= if non-decreasing
103 int slope = eval(m+1) - eval(m); 15 q[++len] = val;
104 if (slope <= 0) 16 } else {
105 j = m; 17 int l=1, r=len;
106 else 18 while (l<r) {
107 i = m+1; 19 int m = (l+r)>>1;
108 } 20 if (q[m] >= val) { // use > if non-decreasing
109 return i; 21 r = m;
110 } 22 } else {
23 l = m+1;
24 }
5 Ternary Search 25 }
26 q[l] = val;
27 }
1 int times = 100; 28 }
2 double left = 0.0; 29 return len;
3 double right = 1000.0; 30 }
4 double ans, m1, m2, v1, v2, third;
5
6 while (times--) {
6.2 Travelling Salesman Problem
7 third = (right - left) / 3.0;
8 m1 = left + third; 1 // ----------------------------------
9 m2 = right - third; 2 // Travelling Salesman Problem (TSP)
10 v1 = eval(m1); 3 // ----------------------------------
11 v2 = eval(m2); 4 // complexity: O(2^N * N)
12 if (v1 < v2) 5
13 left = m1; 6 const int MAXN = 14; // maximum number of nodes in the problem statement
14 else if(v2 < v1) 7 int cost[MAXN][MAXN]; // cost[i][j]: cost to travel from node i to node j
15 right = m2; 8 // make sure cost[i][j] >= 0
16 else 9 int start_index; // OPTIONAL: if you need to remember the start node
Pablo Messina’s ICPC Notebook 6 DYNAMIC PROGRAMMING - 6.3 Knapsack Página 18 de 40
10 12 function DP(i, c)
11 // dp(mask, i): find the minimum cost of visiting all nodes indicated by ’mask’ 13 if i == first
12 // starting from node ’i’. 14 if c >= weight[i] && value[i] > 0 // enough space and worth it
13 // *** OPTIONAL VARIANT: include the cost of returning back to the start node at the end 15 return value[i]
14 // 16 else
15 // * mask: an int whose bits indicate the nodes we want to visit 17 return 0
16 // ** if j-th bit in mask is 1, the j-th node should be visited 18 else
17 // else, the j-th node should be ignored 19 ans = DP(i-1, c)
18 // 20 if c >= weight[i] && value[i] > 0 // enough space and worth it
19 // * i: node we are starting the travel from (i’th bit should be 1 in mask) 21 ans = max(ans, value[i] + DP(i-1, c - weight[i]))
20 int memo[1 << MAXN][MAXN]; // 2^MAXN x MAXN 22 return ans
21 int dp(int mask, int i) { 23
22 // base case 1: problem already solved 24 // -----------
23 int& ans = memo[mask][i]; 25 // BOTTOM-UP
24 if (ans != -1) return ans; 26
25 27 #define MAXN 1000 // max num items
26 // mark i-th node as visited 28 #define MAXC 500 // max capacity
27 int mask2 = mask & ~(1 << i); 29 int value[MAXN];
28 30 int weight[MAXN];
29 // base case 2: nothing else to visit 31 int memo[MAXC+1]; // 0 ... MAXC
30 if (mask2 == 0) return ans = 0; 32 int N, C;
31 // if (mask2 == 0) return ans = cost[i][start_index]; // <--- if returning back to 33
start 34 int dp() {
32 35 // first item (i = 0)
33 // general case: try all possible next nodes 36 memset(memo, 0, sizeof(memo[0]) * (C+1));
34 ans = INT_MAX; 37 if (value[0] > 0) { // worth it
35 for (int j = 0, tmp=mask2; tmp; ++j, tmp>>=1) { 38 rep (c, weight[0], C) {
36 if (tmp & 1) ans = min(ans, cost[i][j] + dp(mask2, j)); 39 memo[c] = value[0];
37 } 40 }
38 41 }
39 // return answer 42 // other items (i = 1 .. N-1)
40 return ans; 43 rep (i, 1, N-1) {
41 } 44 if (value[i] > 0) { // worth it
42 45 invrep(c, C, weight[i]) { // <--- REVERSE ORDER !!
43 int main() { // usage 46 memo[c] = max(memo[c], value[i] + memo[c - weight[i]]);
44 memset(memo, -1, sizeof memo); 47 }
45 start_index = 0; 48 }
46 cout << dp((1 << N)-1, start_index); // <-- mincost of visiting all N nodes starting 49 }
from 0 50 return memo[C];
47 } 51 }
52
6.3 Knapsack 53 // --------------------------------------
54 // VARIANT 2: with reposition of items
1 /* ===================== */ 55 // -------------------------------------
2 /* Knapsack problem : DP */ 56

3 /* ===================== */ 57 // ---------------------------------
4 58 // TOP-DOWN RECURSION (pseudo-code)
5 // -------------------------------------- 59

6 // VARIANT 1: without reposition of items 60 function DP(i, c)


7 // --------------------------------------- 61 if i == first
8 62 if c >= weight[i] && value[i] > 0 // enough space and worth it
9 // --------------------------------- 63 return value[i]
10 // TOP-DOWN RECURSION (pseudo-code) 64 else
11 65 return 0
Pablo Messina’s ICPC Notebook 6 DYNAMIC PROGRAMMING - 6.4 Divide & Conquer Optimization Página 19 de 40
66 else 8 int G,L;
67 ans = DP(i-1, c) 9 ll DP[MAXG+1][MAXL+1];
68 if c >= weight[i] && value[i] > 0 // enough space and worth it 10
69 ans = max(ans, value[i] + DP(i, c - weight[i])) // << i instead of i-1 11 // return cost of forming a group with items in the range i .. j
70 return ans 12 ll group_cost(int i, int j) { ... }
71 13
72 // ----------- 14 /**
73 // BOTTOM-UP 15 Calculates the values of DP[g][l] for l1 <= l <= l2 (a range of cells in row ’g’)
74 16 using divide & conquer optimization
75 #define MAXN 1000 // max num items 17
76 #define MAXC 500 // max capacity 18 DP[g][l] means: given a list of the first ’l’ items, partition them into ’g’ groups,
77 int value[MAXN]; 19 each group consisting of consecutive items (left to right), so that the total
78 int weight[MAXN]; 20 cost of forming those groups is the minimum possible.
79 int memo[2][MAXC + 1]; // 0 .. MAXC 21
80 int N, C; 22 If we form one group at a time, from right to left, this leads to the following
81 23 recursion:
82 int dp() { 24
83 // first item (i = 0) 25 DP[g][l] = min { DP[g-1][k] + group_cost(k,l-1) for k = g-1 .. l-1 }
84 memset(memo, 0, sizeof(memo[0]) * (C+1)); 26 DP[1][l] = group_cost(0, l-1)
85 if (value[0] > 0) { // worth it 27
86 rep (c, weight[0], C) { 28 in other words:
87 memo[0][c] = value[0] * (c / weight[0]); // collect it as many times as you 29
can 30 DP[g][l] = DP[g-1][best_k] + group_cost(best_k,l-1)
88 } 31 where best_k is the left most value of k where the minimum is reached
89 } 32
90 // other items (i = 1 .. N-1) 33 Now, for a given ’g’:
91 int prev = 0, curr = 1; 34
92 rep (i, 1, N-1) { 35 If best_k(g,0) <= best_k(g,1) <= best_k(g,2) <= ... <= best_k(g,L-1) holds
93 rep(c, 0, C) { // <--- INCREASING ORDER !! 36
94 if (c >= weight[i] && value[i] > 0) { // if fits in && worth it 37 Then, we can propagate those best_k’s recursively to reduce the range of
95 memo[curr][c] = max( 38 candidate k’s for each DP[g][l] problem we solve.
96 memo[prev][c], // option 1: don’t take it 39 Using Divide & Conquer, we fill the whole row ’g’ recursively with
97 value[i] + memo[curr][c - weight[i]] // option 2: take it 40 recursion depth O(log(L)), and each recursion layer taking O(L) time.
98 ); 41
99 } else { 42 Doing this for G groups, the total computation cost is O(G*L*log(L))
100 memo[curr][c] = memo[prev][c]; // only option is to skip it 43
101 } 44 */
102 } 45 void fill_row(int g, int l1, int l2, int k1, int k2) {
103 // update prev, curr 46 if (l1 > l2) return; // ensure valid range
104 prev = curr; 47 int lm = (l1+l2)/2; // solve middle case
105 curr = 1-curr; 48 int kmin = max(g-1, k1);
106 } 49 int kmax = min(lm-1, k2);
107 return memo[(N-1)&1][C]; // last item + full capacity 50 int best_k = -1;
108 } 51 ll mincost = LLONG_MAX;
52 rep(k,kmin,kmax) {
6.4 Divide & Conquer Optimization 53 ll tmp = DP[g-1][k] + group_cost(k, lm-1);
54 if (mincost > tmp) mincost = tmp, best_k = k;
1 #include <bits/stdc++.h> 55 }
2 using namespace std; 56 DP[g][lm] = mincost;
3 #define rep(i,a,b) for(int i=a;i<=b;++i) 57 fill_row(g, l1, lm-1, k1, best_k); // solve left cases
4 typedef long long int ll; 58 fill_row(g, lm+1, l2, best_k, k2); // solve right cases
5 59 }
6 #define MAXG 1000 60

7 #define MAXL 1000 61 void fill_dp() {


Pablo Messina’s ICPC Notebook 7 GRAPHS - Página 20 de 40
62 // base: g = 1 44 }
63 rep(l,1,L) DP[1][l] = group_cost(0,l-1); 45 }
64 // other: g >= 2 46 return count;
65 rep(g,2,G) fill_row(g,g,L,0,L); 47 }
66 }
7.2 DFS
7 Graphs
1 // =========================
2 // Depth First Search (DFS)
7.1 BFS 3 // =========================
4 const int MAXN = 1000;
1 const int MAXN = 1000; 5 vector<int> g[MAXN];
2 vector<int> g[MAXN]; // graph 6 bool visited[MAXN];
3 int depth[MAXN]; // bfs depth per node 7 int n;
4 int n; // number of nodes 8
5 9 //recursive
6 void bfs(int s) { 10 void dfs(int u) {
7 memset(depth, -1, sizeof(int) * n); // init depth with -1 11 visited[u] = true;
8 queue<int> q; q.push(s); // init queue and add ’s’ (starting node) 12 for(int v : g[u]) {
9 depth[s] = 0; // s will have depth 0 13 if(!visited[v]) {
10 while (!q.empty()) { // while there are nodes in the queue 14 dfs(v);
11 int u = q.front(); q.pop(); // extract the first node ’u’ from the queue 15 }
12 for (int v : g[u]) { // for each neighbor ’v’ of ’u’ 16 }
13 if (depth[v] == -1) { // if ’v’ has not been visited yet -> visit it 17 }
14 depth[v] = depth[u] + 1; 18
15 q.push(v); 19 //recursive, using depth
16 } 20 int depth[MAXN];
17 } 21 void dfs(int u, int d) {
18 } 22 depth[u] = d;
19 } 23 for(int v : g[u]) {
20 24 if(depth[v] == -1) { // not visited yet
21 //----------------------------- 25 dfs(v, d+1);
22 // Finding connected components 26 }
23 //----------------------------- 27 }
24 28 }
25 int count_cc() { 29
26 static bool visited[MAXN]; 30 //iterative
27 int count = 0; 31 void dfs(int root) {
28 memset(visited, 0, sizeof(bool)*n); 32 stack<int> s;
29 queue<int> q; 33 s.push(root);
30 rep(i,0,n-1) { 34 visited[root] = true;
31 if (!visited[i]) { 35 while (!s.empty()) {
32 count++; 36 int u = s.top(); s.pop();
33 visited[i] = true; 37 for (int v : g[u]) {
34 q.push(i); 38 if (!visited[v]) {
35 while (!q.empty()) { 39 visited[u] = true;
36 int u = q.front(); q.pop(); 40 s.push(v);
37 for (int v : g[u]) { 41 }
38 if (!visited[v]) { 42 }
39 visited[v] = true; 43 }
40 q.push(v); 44 }
41 } 45
42 } 46 //-----------------------------
43 } 47 // Finding connected components
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.3 TopoSort Página 21 de 40
48 //----------------------------- 13 void dfs(int u) {
49 int count_cc() { 14 visited[u] = true;
50 int count = 0; 15 for (int v : g[u]) {
51 memset(visited, 0, sizeof(bool)*n); 16 if (!visited[v])
52 rep(i,0,n-1) { 17 dfs(v);
53 if (!visited[i]) { 18 }
54 count++, dfs(i); 19 sorted.push_back(u);
55 } 20 }
56 } 21
57 return count; 22 void topo_sort() {
58 } 23 memset(visited, false, sizeof(bool) * n);
59 24 sorted.clear();
60 //------------------------------ 25 rep(i,0,n-1)
61 // Flood Fill 26 if (!visited[i])
62 //------------------------------ 27 dfs(i);
63 28 }
64 //explicit graph 29
65 const int DFS_WHITE = -1; 30 // ---------------------------
66 vector<int> dfs_num(DFS_WHITE,n); 31 // option 2: Kahn’s algorithm
67 void floodfill(int u, int color) { 32 // ---------------------------
68 dfs_num[u] = color; 33
69 for (int v : g[u]) { 34 vector<vi> g;
70 if (dfs_num[v] == DFS_WHITE) { 35 int n;
71 floodfill(v, color); 36 vi indegree;
72 } 37 vi sorted;
73 } 38
74 } 39 void compute_indegree() {
75 40 indegree.assign(n, 0);
76 //implicit graph 41 rep(u,0,n-1)
77 int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 42 rep(int v : g[u])
78 const char EMPTY = ’*’; 43 indegree[v]++;
79 int floodfill(int r, int c, char color) { 44 }
80 if (r < 0 || r >= R || c < 0 || c >= C) return 0; // outside grid 45
81 if (grid[r][c] != EMPTY) return 0; // cannot be colored 46 void topoSort() {
82 grid[r][c] = color; 47 sorted.clear();
83 int ans = 1; 48 compute_indegree();
84 rep(i,0,3) ans += floodfill(r + dirs[i][0], c + dirs[i][1], color); 49
85 return ans; 50 queue<int> q;
86 } 51 rep(i,0,n-1)
52 if (indegree[i] == 0)
7.3 TopoSort 53 q.push(i);
54

1 typedef vector<int> vi; 55 while(!q.empty()) {


2 56 int u = q.front(); q.pop();
3 // ---------------------------- 57 sorted.push_back(u);
4 // option 1: tarjan’s algorithm 58 for (int v : g[u]) {
5 // ---------------------------- 59 if(--indegree[v] == 0)
6 // Note: nodes are sorted in reversed order 60 q.push(v);
7 61 }
8 vector<vi> g; // graph 62 }
9 int n; // num of nodes 63 }
10 bool visited[MAXN]; // track visited nodes
11 vi sorted; 7.4 Dijkstra
12
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.5 Minimum Spanning Tree (Kruskal & Prim) Página 22 de 40
1 // complexity: (|E| + |V|) * log |V| 22 rep(i,0,n-1) p[i] = i;
2 #include <bits/stdc++.h> 23 }
3 using namespace std; 24 int findSet(int i) { return (p[i] == i) ? i : (p[i] = findSet(p[i])); }
4 typedef pair<int, int> ii; // (weight, node), in that order 25 bool isSameSet(int i, int j) { return findSet(i) == findSet(j); }
5 26 void unionSet(int i, int j) {
6 vector<vector<ii>> g; // graph 27 if (!isSameSet(i, j)) {
7 int N; // number of nodes 28 int x = findSet(i), y = findSet(j);
8 vector<int> mindist; // min distance from source to each node 29 if (rank[x] > rank[y]) { p[y] = x; }
9 vector<int> parent; // parent of each node in shortest path from source 30 else { p[x] = y; if (rank[x] == rank[y]) rank[y]++; }
10 31 }
11 void dijkstra(int source) { 32 }
12 parent.assign(N, -1); 33 };
13 mindist.assign(N, INT_MAX); 34 int find_mst(int n_nodes, vector<Edge>& edges, vector<vector<ii>>& mst) {
14 mindist[source] = 0; 35 sort(edges.begin(), edges.end());
15 priority_queue<ii, vector<ii>, greater<ii>> q; // minheap 36 UnionFind uf(n_nodes);
16 q.emplace(0, source); 37 mst.assign(n_nodes, vector<ii>());
17 while (!q.empty()) { 38 int mstcost = 0;
18 ii p = q.top(); q.pop(); 39 int count = 1;
19 int u = p.second, dist = p.first; // u = node, dist = mindist from source to u 40 for (auto& e : edges) {
20 if (mindist[u] < dist) continue; // skip outdated improvements 41 int u = e.u, v = e.v, cost = e.cost;
21 for (ii& e : g[u]) { 42 if (!uf.isSameSet(u, v)) {
22 int v = e.second, w = e.first; 43 mstcost += cost;
23 if (mindist[v] > dist + w) { 44 uf.unionSet(u, v);
24 mindist[v] = dist + w; 45 mst[u].emplace_back(v, cost);
25 parent[v] = u; 46 mst[v].emplace_back(u, cost);
26 q.emplace(mindist[v], v); 47 if (++count == n_nodes) break;
27 } 48 }
28 } 49 }
29 } 50 return mstcost;
30 } 51 }
52 }
7.5 Minimum Spanning Tree (Kruskal & Prim) 53
54 /* ============== */
1 #include <bits/stdc++.h> 55 /* METHOD 2: PRIM */
2 #define rep(i,a,b) for (int i=a; i<=b; ++i) 56 /* ============== */
3 using namespace std; 57

4 typedef pair<int,int> ii; 58 struct Edge {


5 59 int u, v, cost;
6 /* ================= */ 60 bool operator<(const Edge& o) const {
7 /* METHOD 1: KRUSKAL */ 61 return cost > o.cost; // we use ’>’ instead of ’<’ so that
8 /* ================= */ 62 // priority_queue<Edge> works as a minheap
9 63 }
10 struct Edge { 64 };
11 int u, v, cost; 65 namespace Prim {
12 bool operator<(const Edge& o) const { 66 bool visited[MAXN];
13 return cost < o.cost; 67 int find_mst(vector<vector<ii>>& g, vector<vector<ii>>& mst) {
14 } 68 int n_nodes = g.size();
15 }; 69 memset(visited, false, sizeof(bool) * n_nodes);
16 namespace Kruskal { 70 mst.assign(n_nodes, vector<ii>());
17 struct UnionFind { 71 priority_queue<Edge> q;
18 vector<int> p, rank; 72 int total_cost = 0;
19 UnionFind(int n) { 73 visited[0] = true;
20 rank.assign(n,0); 74 for (ii& p : g[0]) q.push({0, p.first, p.second});
21 p.resize(n); 75 int count = 1;
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.6 Lowest Commen Ancestor (LCA) Página 23 de 40
76 while (!q.empty()) { 33 // dfs to record direct parents and depths
77 Edge edge = q.top(); q.pop(); 34 void dfs(int u, int p, int depth) {
78 if (visited[edge.v]) continue; 35 anc(u,0) = p;
79 int u = edge.u; 36 D[u] = depth;
80 int v = edge.v; 37 for (int v : (*g)[u]) {
81 int cost = edge.cost; 38 if (D[v] == -1) {
82 visited[v] = true; 39 dfs(v, u, depth + 1);
83 total_cost += cost; 40 }
84 mst[u].emplace_back(v, cost); 41 }
85 mst[v].emplace_back(u, cost); 42 }
86 if (++count == N) break; 43
87 for (ii p : g[v]) { 44 LCA(vector<vector<int>>& _g, int root) {
88 if (visited[p.first]) continue; 45 g = &_g;
89 q.push({v, p.first, p.second}); 46 n = _g.size();
90 } 47 maxe = log2(n);
91 } 48 D.assign(n, -1);
92 return total_cost; 49 A.resize(n * (maxe + 1));
93 } 50 dfs(root, -1, 0);
94 } 51 rep(e, 1, maxe) {
52 rep (u, 0, n-1) {
7.6 Lowest Commen Ancestor (LCA) 53 // u’s 2^e th ancestor is
54 // u’s 2^(e-1) th ancestor’s 2^(e-1) th ancestor
1 /* ============================ */ 55 int a = anc(u,e-1);
2 /* LCA (Lowest Common Ancestor) */ 56 anc(u,e) = (a == -1 ? -1 : anc(a,e-1));
3 /* ============================ */ 57 }
4 #include <bits/stdc++.h> 58 }
5 using namespace std; 59 }
6 #define rep(i,a,b) for (int i=a; i<=b; ++i) 60

7 #define invrep(i,b,a) for (int i=b; i>=a; --i) 61 // move node u "k" levels up towards the root
8 62 // i.e. find the k-th ancestor of u
9 // General comments: 63 int raise(int u, int k) {
10 // * Both of these methods assume that we are working with a connected 64 for (int e = 0; k; e++, k>>=1) if (k&1) u = anc(u,e);
11 // graph ’g’ of ’n’ nodes, and that nodes are compactly indexed from 0 to n-1. 65 return u;
12 // In case you have a forest of trees, a simple trick is to create a fake 66 }
13 // root and connect all the trees to it (make sure to re-index all your nodes) 67

14 // * ’g’ need not be a ’tree’, DFS fill implictly find a tree for you 68 int lca(int u, int v) {
15 // in case you don’t care of the specific tree (e.g. if cycles are not important) 69 if (D[u] < D[v]) swap(u, v);
16 70 u = raise(u, D[u] - D[v]); // raise lowest to same level
17 // ------------------------------------------------------------ 71 if (u == v) return u; // same node, we are done
18 // METHOD 1: SPARSE TABLE - BINARY LIFTING (aka JUMP POINTERS) 72 // raise u and v to their highest ancestors below the LCA
19 // ------------------------------------------------------------ 73 invrep (e, maxe, 0) {
20 // construction: O(|V| log |V|) 74 // greedily take the biggest 2^e jump possible as long as
21 // query: O(log|V|) 75 // u and v still remain BELOW the LCA
22 // ** advantages: 76 if (anc(u,e) != anc(v,e)) {
23 // - the lca query can be modified to compute querys over the path between 2 nodes 77 u = anc(u,e), v = anc(v,e);
24 // - it’s possible to append new leaf nodes to the tree 78 }
25 79 }
26 struct LCA { 80 // the direct parent of u (or v) is lca(u,v)
27 vector<int> A, D; // ancestors, depths 81 return anc(u,0);
28 vector<vector<int>> *g; // pointer to graph 82 }
29 int n, maxe; // num nodes, max exponent 83

30 int& anc(int u, int e) { return A[e * n + u]; } 84 // distance between ’u’ and ’v’
31 int inline log2(int x) { return 31 - __builtin_clz(x); } 85 int dist(int u, int v) {
32 86 return D[u] + D[v] - 2 * D[lca(u,v)];
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.6 Lowest Commen Ancestor (LCA) Página 24 de 40
87 } 140 D[idx++] = depth;
88 // optimized version (in case you already computed lca(u,v)) 141 }
89 int dist(int u, int v, int lca_uv) { 142 }
90 return D[u] + D[v] - 2 * D[lca_uv]; 143 }
91 } 144
92 // get the node located k steps from ’u’ walking towards ’v’ 145 LCA(vector<vector<int>>& _g, int root) {
93 int kth_node_in_path(int u, int v, int k) { 146 g = &_g;
94 int lca_uv = lca(u,v); 147 n = _g.size();
95 if (D[u] - D[lca_uv] >= k) return raise(u, k); 148 H.assign(n, -1);
96 return raise(v, dist(u,v,lca_uv) - k); 149 E.resize(2*n);
97 } 150 D.resize(2*n);
98 151 idx = 0;
99 int add_child(int p, int u) { // optional 152 dfs(root, 0); // euler tour
100 // add to graph 153 int nn = idx; // <-- make sure you use the correct number
101 (*g)[p].push_back(u); 154 int maxe = log2(nn);
102 // update depth 155 DP.resize(nn * (maxe+1));
103 D[u] = D[p] + 1; 156 // build sparse table with bottom-up DP
104 // update ancestors 157 rep(i,0,nn-1) rmq(i,0) = i; // base case
105 anc(u,0) = p; 158 rep(e,1,maxe) { // general cases
106 rep (e, 1, maxe){ 159 rep(i, 0, nn - (1 << e)) {
107 p = anc(p,e-1); 160 // i ... i + 2 ^ (e-1) - 1
108 if (p == -1) break; 161 int i1 = rmq(i,e-1);
109 anc(u,e) = p; 162 // i + 2 ^ (e-1) ... i + 2 ^ e - 1
110 } 163 int i2 = rmq(i + (1 << (e-1)), e-1);
111 } 164 // choose index with minimum depth
112 }; 165 rmq(i,e) = D[i1] < D[i2] ? i1 : i2;
113 166 }
114 // ------------------------------------------ 167 }
115 // METHOD 2: SPARSE TABLE - EULER TOUR + RMQ 168 }
116 // ------------------------------------------ 169
117 // construction: O(2|V| log 2|V|) = O(|V| log |V|) 170 int lca(int u, int v) {
118 // query: O(1) (** assuming that __builtin_clz is mapped to an 171 // get ocurrence indexes in increasing order
119 // efficient processor instruction) 172 int l = H[u], r = H[v];
120 173 if (l > r) swap(l, r);
121 174 // get node with minimum depth in range [l .. r] in O(1)
122 struct LCA { 175 int len = r - l + 1;
123 vector<int> E, D, H; // E = euler tour, D = depth, H = first index of node in euler 176 int e = log2(len);
tour 177 int i1 = rmq(l,e);
124 vector<int> DP // memo for range minimun query 178 int i2 = rmq(r - ((1 << e) - 1), e);
125 vector<vector<int>> *g; // pointer to graph 179 return D[i1] < D[i2] ? E[i1] : E[i2];
126 int idx; // tracks node ocurrences 180 }
127 int n; // number of nodes 181
128 182 int dist(int u, int v) {
129 int& rmq(int i, int e) { return DP[e * idx + i]; } 183 // make sure you use H to retrieve the indexes of u and v
130 inline int log2(int x) { return 31 - __builtin_clz(x); } 184 // within the Euler Tour sequence before using D
131 185 return D[H[u]] + D[H[v]] - 2 * D[H[lca(u,v)]];
132 void dfs(int u, int depth) { 186 }
133 H[u] = idx; // index of first u’s ocurrence 187 }
134 E[idx] = u; // record node ocurrence 188
135 D[idx++] = depth; // record depth 189 // -----------------
136 for (int v : (*g)[u]) { 190 // EXAMPLE OF USAGE
137 if (H[v] == -1) { 191 // -----------------
138 dfs(v, depth + 1); // explore v’s subtree and come back to u 192 int main() {
139 E[idx] = u; // new ocurrence of u 193 // build graph
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.7 Diameter of a Tree Página 25 de 40
194 int n, m; 2 // Tarjan’s Algorithm
195 scanf("%d%d", &n, &m); 3 // -------------------
196 vector<vector<int>> g(n); 4 //references:
197 while (m--) { 5 //https://www.youtube.com/watch?v=jFZsDDB0-vo
198 int u, v; scanf("%d%d", &u, &v); 6 //https://www.hackerearth.com/practice/algorithms/graphs/articulation-points-and-bridges/
199 g[u].push_back(v); tutorial/
200 g[v].push_back(u); 7 //https://www.hackerearth.com/practice/algorithms/graphs/biconnected-components/tutorial/
201 } 8 //http://web.iitd.ac.in/~bspanda/biconnectedMTL776.pdf
202 // init LCA 9 typedef pair<int,int> ii;
203 LCA lca(g,0); 10 const int MAXN = 1000;
204 // answer queries 11 int depth[MAXN];
205 int q; scanf("%d", &q); 12 int low[MAXN];
206 while (q--) { 13 vector<int> g[MAXN];
207 int u, v; scanf("%d%d", &u, &v); 14 stack<ii> edge_stack;
208 printf("LCA(%d,%d) = %d\n", u, v, lca.lca(u,v)); 15
209 printf("dist(%d,%d) = %d\n", u, v, lca.dist(u,v)); 16 void print_and_remove_bicomp(int u, int v) {
210 } 17 puts("biconnected component found:");
211 }; 18 ii uv(u,v);
19 while (true) {
7.7 Diameter of a Tree 20 ii top = edge_stack.top();
21 edge_stack.pop();
1 // ========================== 22 printf("(%d, %d)\n", top.first, top.second);
2 // Find Tree’s Diameter Ends 23 if (top == uv) break;
3 // ========================== 24 }
4 const int MAXN = 10000; 25 }
5 26

6 int farthest_from(vector<vi>& g, int s) { // find farthest node from ’s’ with BFS 27 void dfs(int u, int p, int d) { // (node, parent, depth)
7 static int dist[MAXN]; 28 static num_root_children = 0;
8 memset(dist, -1, sizeof(int) * g.size()); 29 depth[u] = d;
9 int farthest = s; 30 low[u] = d; // u at least can reach itself (ignoring u-p edge)
10 queue<int> q; 31 for(int v : g[u]) {
11 q.push(s); 32 if (v == p) continue; // direct edge to parent -> ignore
12 dist[s] = 0; 33 if (depth[v] == -1) { // exploring a new, unvisited child node
13 while (!q.empty()) { 34 edge_stack.emplace(u,v); // add edge to stack
14 int u = q.front(); q.pop(); 35 dfs(v, u, d + 1); // explore recursively v’s subtree
15 for (int v : g[u]) { 36 // 1) detect articulation points and biconnected components
16 if (dist[v] == -1) { 37 if (p == -1) { // 1.1) special case: if u is root
17 dist[v] = dist[u] + 1; 38 if (++num_root_children == 2) {
18 q.push(v); 39 // we detected that root has AT LEAST 2 children
19 if (dist[v] > dist[farthest]) farthest = v; 40 // therefore root is an articulation point
20 } 41 printf("root = %d is articulation point\n", root);
21 } 42 }
22 } 43 // whenever we come back to the root, we just finished
23 return farthest; 44 // exploring a whole biconnected component
24 } 45 print_and_remove_bicomp(u,v);
25 46 } else if (low[v] >= d) { // 1.2) general case: non-root
26 void find_diameter(vector<vi>& g, int& e1, int& e2) { 47 printf("u = %d is articulation point\n", u);
27 e1 = farthest_from(g, 0); 48 // we entered through and came back to an AP,
28 e2 = farthest_from(g, e1); 49 // so we just finished exploring a whole biconnected component
29 } 50 print_and_remove_bicomp(u,v);
51 }
7.8 Articulation Points, Cut Edges, Biconnected Components 52 // 2) detect cut edges (a.k.a. bridges)
53 if (low[v] > depth[u]) {
1 // ------------------- 54 printf("(u,v) = (%d, %d) is cut edge\n", u, v);
Pablo Messina’s ICPC Notebook 7 GRAPHS - 7.9 Strongly Connected Components Página 26 de 40
55 } 40 ids.assign(n, -1);
56 // propagate low 41 low.resize(n);
57 low[u] = min(low[u], low[v]); 42 instack.assign(n, 0);
58 } else if (depth[v] < d) { // back-edge to proper ancestor 43 ID = 0;
59 edge_stack.emplace(u,v); // add edge to stack 44 rep(u, 0, n-1) if (ids[u] == -1) dfs(u);
60 low[u] = min(low[u], depth[v]); // propagate low 45 }
61 } else { // forward-edge to an already visited descendant 46 };
62 // => do nothing, because this edge was already considered as a 47
63 // back-edge from v -> u 48 // example of usage
64 } 49 int main() {
65 } 50 // read and build graph from standard input
66 } 51 int n, m; cin >> n >> m;
52 vector<vector<int>> g(n);
7.9 Strongly Connected Components 53 while(m--) {
54 int u, v; cin >> u >> v; u--, v--;
1 #include <bits/stdc++.h> 55 g[u].push_back(v);
2 #define rep(i,a,b) for(int i=a; i<=b; ++i) 56 }
3 using namespace std; 57 // find SCCs
4 // ----------------------------------------- 58 tarjanSCC tscc(g);
5 // implementation of Tarjan’s SCC algorithm 59 return 0;
6 struct tarjanSCC { 60 }
7 vector<int> _stack, ids, low;
8 vector<bool> instack; 7.10 Max Flow : Dinic
9 vector<vector<int>>* g;
10 int n, ID; 1 // Time Complexity:
11 void dfs(int u) { 2 // - general worst case: O (|E| * |V|^2)
12 ids[u] = low[u] = ID++; 3 // - unit capacities: O( min(V^(2/3), sqrt(E)) * E)
13 instack[u] = true; 4 // - Bipartite graph (unit capacities) + source & sink (any capacities): O(E sqrt V)
14 _stack.push_back(u); 5
15 for (int v : (*g)[u]) { 6 #include <bits/stdc++.h>
16 if (ids[v] == -1) { 7 using namespace std;
17 dfs(v); 8 typedef long long int ll;
18 low[u] = min(low[v], low[u]); 9
19 } else if (instack[v]) { 10 struct Dinic {
20 low[u] = min(low[v], low[u]); 11 struct edge {
21 } 12 int to, rev;
22 } 13 ll f, cap;
23 if (low[u] == ids[u]) { 14 };
24 // u is the root of a SCC 15
25 // ** here you can do whatever you want 16 vector<vector<edge>> g;
26 // with the SCC just found 17 vector<ll> dist;
27 cout << "SCC found!\n"; 18 vector<int> q, work;
28 // remove SCC from top of the stack 19 int n, sink;
29 while (1) { 20
30 int x = _stack.back(); _stack.pop_back(); 21 bool bfs(int start, int finish) {
31 instack[x] = false; 22 dist.assign(n, -1);
32 if (x == u) break; 23 dist[start] = 0;
33 } 24 int head = 0, tail = 0;
34 } 25 q[tail++] = start;
35 } 26 while (head < tail) {
36 tarjanSCC(vector<vector<int>>& _g) { 27 int u = q[head++];
37 g = &_g; 28 for (const edge &e : g[u]) {
38 n = _g.size(); 29 int v = e.to;
39 _stack.reserve(n); 30 if (dist[v] == -1 and e.f < e.cap) {
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - Página 27 de 40
31 dist[v] = dist[u] + 1; 84 int main() {
32 q[tail++] = v; 85 Dinic din(2);
33 } 86 din.add_edge(0,1,10);
34 } 87 ll mf = din.max_flow(0,1);
35 } 88 }
36 return dist[finish] != -1;
37
38
}
8 Mathematics
39 ll dfs(int u, ll f) {
40 if (u == sink) 8.1 Euclidean Algorithm
41 return f;
42 for (int &i = work[u]; i < (int)g[u].size(); ++i) { 1 typedef long long int ll;
43 edge &e = g[u][i]; 2
44 int v = e.to; 3 inline ll mod(ll x, ll m) { return ((x %= m) < 0) ? x+m : x; }
45 if (e.cap <= e.f or dist[v] != dist[u] + 1) 4
46 continue; 5 /* ============================= */
47 ll df = dfs(v, min(f, e.cap - e.f)); 6 /* GCD (greatest common divisor) */
48 if (df > 0) { 7 /* ============================= */
49 e.f += df; 8 // OPTION 1: using C++ builtin function __gcd
50 g[v][e.rev].f -= df; 9 __gcd(a,b)
51 return df; 10 // OPTION 2: manually usings euclid’s algorithm
52 } 11 int gcd (ll a, ll b) {
53 } 12 while (b) { a %= b; swap(a,b); }
54 return 0; 13 return a;
55 } 14 }
56 15
57 Dinic(int n) { 16 /* ============ */
58 this->n = n; 17 /* extended GCD */
59 g.resize(n); 18 /* ============ */
60 dist.resize(n); 19 // extended euclid’s algorithm: find g, x, y such that
61 q.resize(n); 20 // a * x + b * y = g = gcd(a, b)
62 } 21 // The algorithm finds a solution (x0,y0) but there are infinite more:
63 22 // x = x0 + n * (b/g)
64 void add_edge(int u, int v, ll cap) { 23 // y = y0 - n * (a/g)
65 edge a = {v, (int)g[v].size(), 0, cap}; 24 // where n is integer, are the set of all solutions
66 edge b = {u, (int)g[u].size(), 0, 0}; //Poner cap en vez de 0 si la arista es 25
bidireccional 26 // --- version 1: iterative
67 g[u].push_back(a); 27 ll gcdext(ll a, ll b, ll& x, ll& y) {
68 g[v].push_back(b); 28 ll r2, x2, y2, r1, x1, y1, r0, x0, y0, q;
69 } 29 r2 = a, x2 = 1, y2 = 0;
70 30 r1 = b, x1 = 0, y1 = 1;
71 ll max_flow(int source, int dest) { 31 while (r1) {
72 sink = dest; 32 q = r2 / r1;
73 ll ans = 0; 33 r0 = r2 % r1;
74 while (bfs(source, dest)) { 34 x0 = x2 - q * x1;
75 work.assign(n, 0); 35 y0 = y2 - q * y1;
76 while (ll delta = dfs(source, LLONG_MAX)) 36 r2 = r1, x2 = x1, y2 = y1;
77 ans += delta; 37 r1 = r0, x1 = x0, y1 = y0;
78 } 38 }
79 return ans; 39 ll g = r2; x = x2, y = y2;
80 } 40 if (g < 0) g = -g, x = -x, y = -y; // make sure g > 0
81 }; 41 // for debugging (in case you think you might have bugs)
82 42 // assert (g == a * x + b * y);
83 // usage 43 // assert (g == __gcd(abs(a),abs(b)));
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.2 Primality Test Página 28 de 40
44 return g; 97 /* Linear Congruence Equation */
45 } 98 /* ========================== */
46 99 // recommended reading:
47 // --- version 2: recursive 100 // http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/linear-congruences.
48 ll gcdext(ll a, ll b, ll& x, ll& y) { article.pdf
49 if (a == 0) { 101
50 x = 0, y = 1; 102 // find smallest integer x (mod m) that solves the equation
51 return b; 103 // a * x = b (mod m)
52 } 104 bool lincongeq(ll a, ll b, ll m, ll& x) {
53 ll x1, y1; 105 assert (m > 0);
54 ll g = gcdext(b % a, a, x1, y1); 106 a = mod(a,m);
55 x = y1 - (b / a) * x1; 107 b = mod(b,m);
56 y = x1; 108 ll s, t;
57 return g; 109 ll g = gcdext(a,m,s,t);
58 } 110 if (b % g == 0) {
59 111 ll bb = b/g;
60 /* ====================== */ 112 ll mm = m/g;
61 /* multiplicative inverse */ 113 ll n = -s*bb/mm;
62 /* ====================== */ 114 x = s*bb + n*mm;
63 // find x such that a * x = 1 (mod m) 115 if (x < 0) x += mm;
64 // this is the same as finding x, y such that 116 // for debugging
65 // a * x + m * y = 1, which can be done with gcdext 117 // assert (0 <= x and x < m);
66 // and then returning x (mod m) 118 // assert (mod(a*x,m) == b);
67 ll mulinv(ll a, ll m) { 119 return true;
68 ll x, y; 120 }
69 if (gcdext(a, m, x, y) == 1) return mod(x, m); // make sure 0 <= x < m 121 return false;
70 return -1; // no inverse exists 122 }
71 }
72 8.2 Primality Test
73 /* =========================== */
74 /* Linear Diophantine Equation */ 1 // ===============
75 /* =========================== */ 2 // trial division
76 // recommended readings: 3 //=================
77 // http://gauss.math.luc.edu/greicius/Math201/Fall2012/Lectures/linear-diophantine. 4 // complexity: ~O( sqrt(x) )
article.pdf 5 bool isPrime(int x) {
78 // http://mathonline.wikidot.com/solutions-to-linear-diophantine-equations 6 for (int d = 2; d * d <= x; d++) {
79 7 if (x % d == 0)
80 // find intengers x and y such that a * x + b * y = c 8 return false;
81 bool lindiopeq(ll a, ll b, ll c, ll& x, ll& y) { 9 }
82 if (a == 0 and b == 0) { // special case 10 return true;
83 if (c == 0) { x = y = 0; return true; } 11 }
84 return false; 12
85 } 13 // =======================================
86 // general case 14 // trial division with precomputed primes
87 ll s, t; 15 // =======================================
88 ll g = gcdext(a,b,s,t); 16 // complexity: ~O( sqrt(x)/log(sqrt(x)) )
89 if (c % g == 0) { 17 // + time of precomputing primes
90 x = s*(c/g), y = t*(c/g); 18 bool isPrime(int x, vector<int>& primes) {
91 return true; 19 for (int p : primes) {
92 } 20 if (p*p > x) break;
93 return false; 21 if (p % x == 0)
94 } 22 return false;
95 23 }
96 /* ========================== */ 24 return true;
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.3 Prime Factorization Página 29 de 40
25 } 79 }
26 80
27 81 bool MillerRabin(u64 n) { // returns true if n is prime, else returns false.
28 // ============= 82 if (n < 2)
29 // Miller-Rabin 83 return false;
30 // ============= 84
31 // complexity: O (k * log^3(n)) 85 int r = 0;
32 // references: 86 u64 d = n - 1;
33 // https://cp-algorithms.com/algebra/primality_tests.html 87 while ((d & 1) == 0) {
34 // https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Complexity 88 d >>= 1;
35 using u64 = uint64_t; 89 r++;
36 using u128 = __uint128_t; 90 }
37 91
38 u64 binpower(u64 base, u64 e, u64 mod) { 92 for (int a : {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}) {
39 u64 result = 1; 93 if (n == a)
40 base %= mod; 94 return true;
41 while (e) { 95 if (check_composite(n, a, d, r))
42 if (e & 1) 96 return false;
43 result = (u128)result * base % mod; 97 }
44 base = (u128)base * base % mod; 98 return true;
45 e >>= 1; 99 }
46 }
47 return result; 8.3 Prime Factorization
48 }
49 1 //=====================
50 bool check_composite(u64 n, u64 a, u64 d, int s) { 2 // Prime Factorization
51 u64 x = binpower(a, d, n); 3 //=====================
52 if (x == 1 || x == n - 1) 4 // reference: https://cp-algorithms.com/algebra/factorization.html
53 return false; 5
54 for (int r = 1; r < s; r++) { 6 // method 1: trial division
55 x = (u128)x * x % n; 7 // complexity: ~ O( sqrt(n) + log_2(n) )
56 if (x == n - 1) 8 vector<int> trial_division(int n) {
57 return false; 9 vector<int> factors;
58 } 10 for (int d = 2; d*d <= n; d++) {
59 return true; 11 while (n % d == 0) {
60 }; 12 factors.push_back(d);
61 13 if ((n /= d) == 1) return factors;
62 bool MillerRabin(u64 n) { // returns true if n is probably prime, else returns false. 14 }
63 if (n < 4) 15 }
64 return n == 2 || n == 3; 16 if (n > 1) factors.push_back(n);
65 17 return factors;
66 int s = 0; 18 }
67 u64 d = n - 1; 19
68 while ((d & 1) == 0) { 20 // method 2: precomputed primes
69 d >>= 1; 21 // complexity: ~ O( sqrt(n) / log(sqrt(n)) + log_2(n) )
70 s++; 22 // + time of precomputing primes
71 } 23 vector<int> trial_division_precomp(int n, vector<int>& primes) {
72 24 vector<int> factors;
73 for (int i = 0; i < iter; i++) { 25 for (int d : primes) {
74 int a = 2 + rand() % (n - 3); 26 if (d*d > n) break;
75 if (check_composite(n, a, d, s)) 27 while (n % d == 0) {
76 return false; 28 factors.push_back(d);
77 } 29 if ((n /= d) == 1) return factors;
78 return true; 30 }
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.4 Binary modular exponentiation Página 30 de 40
31 } 14 // choose(n,0) = choose(n,n) = 1
32 if (n > 1) factors.push_back(n); 15
33 return factors; 16 // 1.1) DP top-down
34 } 17 ll memo[MAXN+1][MAXN+1];
35 18 ll choose(int n, int k) {
36 //==================================== 19 ll& ans = memo[n][k];
37 // Prime Factorization of Factorials 20 if (ans != -1) return ans;
38 //==================================== 21 if (k == 0) return ans = 1;
39 // references: 22 if (n == k) return ans = 1;
40 // http://mathforum.org/library/drmath/view/67291.html 23 if (n < k) return ans = 0;
41 // https://janmr.com/blog/2010/10/prime-factors-of-factorial-numbers/ 24 return ans = (choose(n-1,k) + choose(n-1,k-1)) % MOD;
42 #define umap unordered_map 25 }
43 umap<int,int> factorial_prime_factorization(int n, vector<int>& primes) { 26
44 umap<int,int> prime2exp; 27 // 1.2) DP bottom-up
45 for (int p : primes) { 28 ll choose[MAXN+1][MAXN+1];
46 if (p > n) break; 29 rep(m,1,MAXN) {
47 int e = 0; 30 choose[m][0] = choose[m][m] = 1;
48 int tmp = n; 31 rep(k,1,m-1) choose[m][k] = (choose[m-1][k] + choose[m-1][k-1]) % MOD;
49 while ((tmp /= p) > 0) e += tmp; 32 }
50 if (e > 0) prime2exp[p] = e; 33
51 } 34 // -------------------------------------------------
52 return prime2exp; 35 // method 3: factorials and multiplicative inverse
53 } 36 // n! / (k! * (n-k)!) = n! * (k! * (n-k)!)^-1 (MOD N)
37 // we need to find the multiplicative inverse of (k! * (n-k)!) MOD N
8.4 Binary modular exponentiation 38
39 ll fac[MAXN+1];
40 ll choose_memo[MAXN+1][MAXN+1];
1 // compute a^b (mod m) 41 void init() {
2 int binary_exp(int a, int b, int m) { 42 fac[0] = 1;
3 a %= m; 43 rep(i,1,MAXN) fac[i] = (i * fac[i-1]) % MOD;
4 int res = 1; 44 memset(choose_memo, -1, sizeof choose_memo);
5 while (b > 0) { 45 }
6 if (b&1) res = (res * a) % m; 46 ll choose_mod(int n, int k) {
7 a = (a * a) % m; 47 if (choose_memo[n][k] != -1) return choose_memo[n][k];
8 b >>= 1; 48 return choose_memo[n][k] = mul(fac[n], mulinv(mul(fac[k], fac[n-k])));
9 } 49 }
10 return res;
11 } 8.6 Modular Multinomial Coefficient
8.5 Modular Binomial Coefficient 1 typedef long long int ll;
2 const ll MOD = 1000000007ll; // a prime number
1 #define rep(i,a,b) for(int i = a; i <= b; ++i) 3 const int MAXN = 1000;
2 typedef long long int ll; 4
3 const ll MOD = 1000000007ll; // a prime number 5 /* ===================== */
4 const int MAXN = 1000; 6 /* MODULAR MULTINOMIAL */
5 7 /* ===================== */
6 /* ================== */ 8
7 /* MODULAR BINOMIAL */ 9 ll memo[MAXN+1][MAXN+1];
8 /* ================== */ 10 ll choose(int n, int k) {
9 // choose_mod(n,k) = n! / (k! * (n-k)!) % MOD 11 ll& ans = memo[n][k];
10 12 if (ans != -1) return ans;
11 // --------------------- 13 if (k == 0) return ans = 1;
12 // method 1: DP 14 if (n == k) return ans = 1;
13 // choose(n,k) = (choose(n-1,k-1) + choose(n-1,k)) % MOD 15 if (n < k) return ans = 0;
Pablo Messina’s ICPC Notebook 8 MATHEMATICS - 8.7 Chinese Remainder Theorem (CRT) Página 31 de 40
16 return ans = (choose(n-1,k) + choose(n-1,k-1)) % MOD; 39 // sol = r1 + m1 * (r2-r1)/g * x’ (mod LCM(m1,m2))
17 } 40 // where x’ comes from
18 41 // m1 * x’ + m2 * y’ = g = GCD(m1,m2)
19 // reference: https://math.stackexchange.com/a/204209/503889 42 // where x’ and y’ are the values found by extended euclidean algorithm (gcdext)
20 ll multinomial(vector<int> ks) { 43 // Useful references:
21 int n = 0; 44 // https://codeforces.com/blog/entry/61290
22 ll ans = 1; 45 // https://forthright48.com/chinese-remainder-theorem-part-1-coprime-moduli
23 for (int k : ks) { 46 // https://forthright48.com/chinese-remainder-theorem-part-2-non-coprime-moduli
24 n += k; 47 // ** Note: this solution works if lcm(m1,m2) fits in a long long (64 bits)
25 ans = (ans * choose(n,k)) % MOD; 48 pair<ll,ll> CRT(ll r1, ll m1, ll r2, ll m2) {
26 } 49 ll g, x, y; g = gcdext(m1, m2, x, y);
27 return ans; 50 if ((r1 - r2) % g != 0) return {-1, -1}; // no solution
28 } 51 ll z = m2/g;
52 ll lcm = m1 * z;
8.7 Chinese Remainder Theorem (CRT) 53 ll sol = add(mod(r1, lcm), m1*mul(mod(x,z),mod((r2-r1)/g,z),z), lcm);
54 // for debugging (in case you think you might have bugs)
1 #include <bits/stdc++.h> 55 // assert (0 <= sol and sol < lcm);
2 typedef long long int ll; 56 // assert (sol % m1 == r1 % m1);
3 using namespace std; 57 // assert (sol % m2 == r2 % m2);
4 58 return {sol, lcm}; // solution + lcm(m1,m2)
5 inline ll mod(ll x, ll m) { return ((x %= m) < 0) ? x+m : x; } 59 }
6 inline ll mul(ll x, ll y, ll m) { return (x * y) % m; } 60

7 inline ll add(ll x, ll y, ll m) { return (x + y) % m; } 61 // ==============================================


8 62 // CRT for a system of N modular linear equations
9 // extended euclidean algorithm 63 // ==============================================
10 // finds g, x, y such that 64 // Args:
11 // a * x + b * y = g = GCD(a,b) 65 // r = array of remainders
12 ll gcdext(ll a, ll b, ll& x, ll& y) { 66 // m = array of modules
13 ll r2, x2, y2, r1, x1, y1, r0, x0, y0, q; 67 // n = length of both arrays
14 r2 = a, x2 = 1, y2 = 0; 68 // Output:
15 r1 = b, x1 = 0, y1 = 1; 69 // a pair {X, lcm} where X is the solution of the sytemm
16 while (r1) { 70 // X = r[i] (mod m[i]) for i = 0 ... n-1
17 q = r2 / r1; 71 // and lcm = LCM(m[0], m[1], ..., m[n-1])
18 r0 = r2 % r1; 72 // if there is no solution, the output is {-1, -1}
19 x0 = x2 - q * x1; 73 // ** Note: this solution works if LCM(m[0],...,m[n-1]) fits in a long long (64 bits)
20 y0 = y2 - q * y1; 74 pair<ll,ll> CRT(ll* r, ll* m, int n) {
21 r2 = r1, x2 = x1, y2 = y1; 75 ll r1 = r[0], m1 = m[0];
22 r1 = r0, x1 = x0, y1 = y0; 76 rep(i,1,n-1) {
23 } 77 ll r2 = r[i], m2 = m[i];
24 ll g = r2; x = x2, y = y2; 78 ll g, x, y; g = gcdext(m1, m2, x, y);
25 if (g < 0) g = -g, x = -x, y = -y; // make sure g > 0 79 if ((r1 - r2) % g != 0) return {-1, -1}; // no solution
26 // for debugging (in case you think you might have bugs) 80 ll z = m2/g;
27 // assert (g == a * x + b * y); 81 ll lcm = m1 * z;
28 // assert (g == __gcd(abs(a),abs(b))); 82 ll sol = add(mod(r1, lcm), m1*mul(mod(x,z),mod((r2-r1)/g,z),z), lcm);
29 return g; 83 r1 = sol;
30 } 84 m1 = lcm;
31 85 }
32 // ============================================== 86 // for debugging (in case you think you might have bugs)
33 // CRT for a system of 2 modular linear equations 87 // assert (0 <= r1 and r1 < m1);
34 // ============================================== 88 // rep(i,0,n-1) assert (r1 % m[i] == r[i]);
35 // We want to find X such that: 89 return {r1, m1};
36 // 1) x = r1 (mod m1) 90 }
37 // 2) x = r2 (mod m2)
38 // The solution is given by:
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 8.8 Theorems Página 32 de 40
8.8 Theorems 43 }
44
8.8.1 Pick’s Theorem 45 // calculates the cross product (b - a) x (c - a)
46 // and returns orientation:
P
A=I+ 2 −1 47 // LEFT (1): c is to the left of ray (a -> b)
48 // RIGHT (-1): c is to the right of ray (a -> b)
49 // COLLINEAR (0): c is collinear to ray (a -> b)
9 Geometry 50
51
// inspired by: https://www.geeksforgeeks.org/orientation-3-ordered-points/
int orientation(Point& a, Point& b, Point& c) {
52 ll tmp = cross(a,b,c);
9.1 Geometry 2D Utils 53 return tmp < 0 ? -1 : tmp == 0 ? 0 : 1; // sign
54 }
1 #include <bits/stdc++.h> 55

2 using namespace std; 56 /* ======================================================= */


3 typedef long long int ll; 57 /* Check if a segment is below another segment (wrt a ray) */
4 // ------------------------------- 58 /* ======================================================= */
5 const double PI = acos(-1); 59 // i.e: check if a segment is intersected by the ray first
6 const double EPS = 1e-8; 60 // Assumptions:
7 61 // 1) for each segment:
8 /* =========================== */ 62 // p1 should be LEFT (or COLLINEAR) and p2 should be RIGHT (or COLLINEAR) wrt ray
9 /* Example of Point Definition */ 63 // 2) segments do not intersect each other
10 /* =========================== */ 64 // 3) segments are not collinear to the ray
11 template<typename T> 65 // 4) the ray intersects all segments
12 struct Point<T> { // 2D 66 struct Segment { Point p1, p2;};
13 T x, y; 67 Segment segments[MAXN]; // array of line segments
14 bool operator==(const Point<T>& p) const { return x==p.x && y == p.y; } 68 bool is_si_below_sj(int i, int j) { // custom comparator based on cross product
15 Point<T> operator+(const Point<T>& p) const { return {x+p.x, y+p.y}; } 69 Segment& si = segments[i];
16 Point<T> operator-(const Point<T>& p) const { return {x-p.x, y-p.y}; } 70 Segment& sj = segments[j];
17 Point<T> operator*(T d) const { return {x*d, y*d}; } 71 return (si.p1.x >= sj.p1.x) ?
18 Point<double> cast() { return {(double)x, (double)y}; } 72 cross(si.p1, sj.p2, sj.p1) > 0:
19 T norm2() { return x*x + y*y; } 73 cross(sj.p1, si.p1, si.p2) > 0;
20 double norm() { return sqrt(norm2()); } 74 }
21 T dot(const Point<T>& p) const { return x*p.x + y*p.y; } 75 // this can be used to keep a set of segments ordered by order of intersection
22 T cross(const Point<T>& p) const { return x*p.y - y*p.x; } 76 // by the ray, for example, active segments during a SWEEP LINE
23 double angle() { 77 set<int, bool(*)(int,int)> active_segments(is_si_below_sj); // ordered set
24 double angle = atan2(y, x); 78

25 if (angle < 0) angle += 2 * PI; 79 /* ======================= */


26 return angle; 80 /* Rectangle Intersection */
27 } 81 /* ======================= */
28 Point<double> unit() { 82 bool do_rectangles_intersect(Point& dl1, Point& ur1, Point& dl2, Point& ur2) {
29 double d = norm(); 83 return max(dl1.x, dl2.x) <= min(ur1.x, ur2.x) && max(dl1.y, dl2.y) <= min(ur1.y, ur2.
30 return {x/d,y/d}; y);
31 } 84 }
32 }; 85

33 86 /* ========================= */
34 /* ========================================================= */ 87 /* Line Segment Intersection */
35 /* Cross Product -> orientation of point with respect to ray */ 88 /* ========================= */
36 /* ========================================================= */ 89 // returns whether segments p1q1 and p2q2 intersect, inspired by:
37 // cross product (b - a) x (c - a) 90 // https://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
38 ll cross(Point& a, Point& b, Point& c) { 91 bool do_segments_intersect(Point& p1, Point& q1, Point& p2, Point& q2) {
39 ll dx0 = b.x - a.x, dy0 = b.y - a.y; 92 int o11 = orientation(p1, q1, p2);
40 ll dx1 = c.x - a.x, dy1 = c.y - a.y; 93 int o12 = orientation(p1, q1, q2);
41 return dx0 * dy1 - dx1 * dy0; 94 int o21 = orientation(p2, q2, p1);
42 // return (b - a).cross(c - a); // alternatively, using struct function 95 int o22 = orientation(p2, q2, q1);
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.2 Geometry 3D Utils Página 33 de 40
96 if (o11 != o12 and o21 != o22) // general case -> non-collinear intersection 150 }
97 return true; 151
98 if (o11 == o12 and o11 == 0) { // particular case -> segments are collinear 152 /* ==================================== */
99 Point dl1 = {min(p1.x, q1.x), min(p1.y, q1.y)}; 153 /* Point - Line / Line Segment distance */
100 Point ur1 = {max(p1.x, q1.x), max(p1.y, q1.y)}; 154 /* ==================================== */
101 Point dl2 = {min(p2.x, q2.x), min(p2.y, q2.y)}; 155 // reference: https://stackoverflow.com/questions/849211/shortest-distance-between-a-
102 Point ur2 = {max(p2.x, q2.x), max(p2.y, q2.y)}; point-and-a-line-segment
103 return do_rectangles_intersect(dl1, ur1, dl2, ur2); 156
104 } 157 // get distance between p and projection of p on line <- a - b ->
105 return false; 158 double point_line_dist(Point& p, Point& a, Point& b) {
106 } 159 Point d = b-a;
107 160 double t = d.dot(p-a) / d.norm2();
108 /* ======================== */ 161 return (a + d * t - p).norm();
109 /* Line - Line Intersection */ 162 }
110 /* ======================== */ 163
111 ll det(Point& a, Point& b) { return a.x * b.y - a.y * b.x; } 164 // get distance between p and truncated projection of p on segment a -> b
112 // return whether straight lines <-a1-b1-> and <-a2-b2-> intersect each other 165 double point_segment_dist(Point& p, Point& a, Point& b) {
113 // if they intersect, we assign values to t1 and t2 such that 166 if (a==b) return (p-a).norm(); // segment is a single point
114 // a1 + (b1 - a1) * t1 == a2 + (b2 - a2) * t2 167 Point d = b-a; // direction
115 bool find_line_line_intersection(Point& a1, Point& b1, Point& a2, Point& b2, 168 double t = d.dot(p-a) / d.norm2();
116 double& t1, double& t2) { 169 if (t <= 0) return (p-a).norm(); // truncate left
117 Point d1 = b1 - a1; 170 if (t >= 1) return (p-b).norm(); // truncate right
118 Point d2 = b2 - a2; 171 return (a + d * t - p).norm();
119 Point _d2 = d2 * -1; 172 }
120 ll detA = det(d1, _d2); 173
121 if (detA == 0) return false; // parallel lines 174 /* ====================================== */
122 Point b = a2 - a1; 175 /* Straight Line Hashing (integer coords) */
123 t1 = (double)det(b, _d2)/(double)detA; 176 /* ====================================== */
124 t2 = (double)det(d1, b)/(double)detA; 177 // task: given 2 points p1, p2 with integer coordinates, output a unique
125 return true; 178 // representation {a,b,c} such that a*x + b*y + c = 0 is the equation
126 } 179 // of the straight line defined by p1, p2. This representation must be
127 180 // unique for each straight line, no matter which p1 and p2 are sampled.
128 181 struct Point { ll x, y; };
129 /* =================== */ 182 tuple<ll,ll,ll> hash_line(const Point& p1, const Point& p2) {
130 /* Circle Intersection */ 183 ll a = p1.y - p2.y;
131 /* =================== */ 184 ll b = p2.x - p1.x;
132 struct Circle { double x, y, r; } 185 ll c = p1.x * (p2.y - p1.y) - p1.y * (p2.x - p1.x);
133 bool is_fully_outside(double r1, double r2, double d_sqr) { 186 ll sgn = (a < 0 or (a == 0 and b < 0)) ? -1 : 1;
134 double tmp = r1 + r2; 187 ll g = __gcd(abs(a), __gcd(abs(b), abs(c))) * sgn;
135 return d_sqr > tmp * tmp; 188 return make_tuple(a/g, b/g, c/g);
136 } 189 }
137 bool is_fully_inside(double r1, double r2, double d_sqr) { 190 // task: given 2 points p1 and p2 with integer coords, return a pair {a, b}
138 if (r1 > r2) return false; 191 // which is unique for all straight lines having the same slope as
139 double tmp = r2 - r1; 192 // the straight line that goes through p1 and p2
140 return d_sqr < tmp * tmp; 193 pair<ll,ll> hash_slope(const Point& p1, const Point& p2) {
141 } 194 ll dx = p2.x - p1.x;
142 bool do_circles_intersect(Circle& c1, Circle& c2) { 195 ll dy = p2.y - p1.y;
143 double dx = c1.x - c2.x; 196 ll sgn = (dx < 0 or (dx == 0 and dy < 0)) ? -1 : 1;
144 double dy = c1.y - c2.y; 197 ll g = __gcd(abs(dx), abs(dy)) * sgn;
145 double d_sqr = dx * dx + dy * dy; 198 return {dx/g, dy/g};
146 if (is_fully_inside(c1.r, c2.r, d_sqr)) return false; 199 }
147 if (is_fully_inside(c2.r, c1.r, d_sqr)) return false;
148 if (is_fully_outside(c1.r, c2.r, d_sqr)) return false; 9.2 Geometry 3D Utils
149 return true;
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.3 Polygon Algorithms Página 34 de 40
1 /* =========================== */ 9.3 Polygon Algorithms
2 /* Example of Point Definition */
3 /* =========================== */ 1 #include <bits/stdc++.h>
4 struct Point { // 3D 2 #define rep(i,a,b) for(int i = a; i <= b; ++i)
5 double x, y, z; 3
6 bool operator==(const Point& p) const { return x==p.x and y==p.y and z==p.z; } 4 // ----- Utils ------
7 Point operator+(const Point& p) const { return {x+p.x, y+p.y, z+p.z}; } 5 const double EPS = 1e-8;
8 Point operator-(const Point& p) const { return {x-p.x, y-p.y, z-p.z}; } 6 struct Point {
9 Point operator*(double d) const { return {x*d, y*d, z*d}; } 7 ll x, y;
10 double norm2() { return x*x + y*y + z*z; } 8 Point operator-(const Point& p) const { return {x - p.x, y - p.y}; }
11 double norm() { return sqrt(norm2()); } 9 Point operator+(const Point& p) const { return {x + p.x, y + p.y}; }
12 double dot(const Point& p) { return x*p.x + y*p.y + z*p.z; } 10 ll cross(const Point& p) const { return x*p.y - y*p.x; }
13 Point cross(Point& p) { 11 ll dot(const Point& p) const { return x*p.x + y*p.y; }
14 return { 12 };
15 y*p.z - z*p.y, 13 ll cross(Point& a, Point& b, Point& c) {
16 z*p.x - x*p.z, 14 ll dx0 = b.x - a.x, dy0 = b.y - a.y;
17 x*p.y - y*p.x 15 ll dx1 = c.x - a.x, dy1 = c.y - a.y;
18 }; 16 return dx0 * dy1 - dx1 * dy0;
19 } 17 }
20 Point unit() { 18 int orientation(Point& a, Point& b, Point& c) {
21 double d = norm(); 19 ll tmp = cross(a,b,c);
22 return {x/d, y/d, z/d}; 20 return tmp < 0 ? -1 : tmp == 0 ? 0 : 1; // sign
23 } 21 }
24 static Point from_sphere_coords(double r, double u, double v) { 22
25 return { 23 /* ======================================== */
26 r*cos(u)*cos(v), 24 /* Area of 2D non self intersecting Polygon */
27 r*cos(u)*sin(v), 25 /* ======================================== */
28 r*sin(u) 26 //based on Green’s Theorem:
29 }; 27 //http://math.blogoverflow.com/2014/06/04/greens-theorem-and-area-of-polygons/
30 } 28 // ** points must be sorted ccw or cw
31 }; 29 double polygon_area(vector<Point>& pol) {
32 // compute angle (0 <= angle <= PI) between vectors a and b 30 int n = pol.size()
33 // ** for better performance, the norms can be precomputed 31 double area = 0;
34 // or norms can be ommited altogether if a and b are unit vectors 32 for (int i = n-1, j = 0; j < n; i = j++) {
35 double angle_between(Point& a, Point& b) { 33 area += (pol[i].x + pol[j].x) * (pol[j].y - pol[i].y);
36 return acos(a.dot(b)/(a.norm() * b.norm())); 34 }
37 } 35 return area * 0.5; // use abs(area * 0.5) if points are cw
38 // check if point p belongs to the sphere arc from a to b. 36 }
39 // ** this assumes that a and b are points on a sphere centered at (0,0,0), 37
40 // and the sphere arc from a to b is the shortest path on the sphere connecting them 38 /* ================ */
41 const double EPS = 1e-8; 39 /* Point in Polygon */
42 bool point_in_arc(Point& a, Point& b, Point& p) { 40 /* ================ */
43 double angle_ab = angle_between(a, b); 41
44 double angle_ap = angle_between(a, p); 42 // -----------------------------
45 if (angle_ap > angle_ab) return false; 43 // 1) Convex Polygons
46 Point n = a.cross(b); 44
47 Point c_hat = n.cross(a).unit(); 45 // 1.1) O(N) method
48 double R = a.norm(); 46 bool point_in_convexhull(Point& p, vector<Point>& ch) {
49 Point a_hat = a * (1./R); 47 int n = ch.size();
50 Point a_rotated = (a_hat * cos(angle_ap) + c_hat * sin(angle_ap)) * R; 48 for (int i=n-1, j=0; j<n; i=j++) {
51 return (p - a_rotated).norm() < EPS; 49 if (cross(ch[i], ch[j], p) < 0) return false;
52 } 50 }
51 return true;
52 }
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.3 Polygon Algorithms Página 35 de 40
53 107 }
54 // 1.2) O(log N) method 108
55 bool point_in_triangle(Point& a, Point& b, Point& c, Point& x) { 109 /* ================================= */
56 return cross(a, b, x) >= 0 and cross(b, c, x) >= 0 and cross(c, a, x) >= 0; 110 /* Find extreme point in Convex Hull */
57 } 111 /* ================================= */
58 bool point_in_convexhull(Point& p, vector<Point>& ch) { 112 // given two points a and b defining a vector a -> b, and given a convex hull with points
59 if (cross(ch[0], ch[1], p) < 0) return false; 113 // sorted ccw, find the index in the convex hull of the extreme point.
60 if (cross(ch[0], ch.back(), p) > 0) return false; 114 // ** the extreme point is the "leftmost" point in the convex hull with respect to the
61 int l = 2, r = ch.size() - 1; 115 // vector a -> b (if there are 2 leftmost points, pick anyone)
62 while (l < r) { 116 int extreme_point_index(Point &a, Point &b, vector<Point> &ch) {
63 int m = (l+r) >> 1; 117 int n = ch.size();
64 if (cross(ch[0], ch[m], p) <= 0) r = m; 118 Point v = b - a;
65 else l = m+1; 119 v = Point(-v.y, v.x); // to find the leftmost point
66 } 120 if (v.dot(ch[0]) >= v.dot(ch[1]) && v.dot(ch[0]) >= v.dot(ch[n - 1])) {
67 return point_in_triangle(ch[0], ch[l-1], ch[l], p); 121 return 0;
68 } 122 }
69 123 int l = 0, r = n;
70 // ---------------------------------------------- 124 while (true) {
71 // 2) General methods: for complex / simple polygons 125 int m = (l + r) / 2;
72 126 if (v.dot(ch[m]) >= v.dot(ch[m + 1]) && v.dot(ch[m]) >= v.dot(ch[m - 1])) {
73 /* Nonzero Rule (winding number) */ 127 return m;
74 bool inPolygon_nonzero(Point p, vector<Point>& pts) { 128 }
75 int wn = 0; // winding number 129 int d1 = v.dot(ch[l + 1] - ch[l]) > 0;
76 Point prev = pts.back(); 130 int d2 = v.dot(ch[m + 1] - ch[m]) > 0;
77 rep (i, 0, (int)pts.size() - 1) { 131 int a = v.dot(ch[m]) > v.dot(ch[l]);
78 Point curr = pts[i]; 132 if (d1) { if (d2 && a) l = m; else r = m; }
79 if (prev.y <= p.y) { 133 else { if (!d2 && a) r = m; else l = m; }
80 if (p.y < curr.y && cross(prev, curr, p) > 0) 134 }
81 ++ wn; // upward & left 135 }
82 } else { 136
83 if (p.y >= curr.y && cross(prev, curr, p) < 0) 137 /* ========================================= */
84 -- wn; // downward & right 138 /* Line Segment and Convex Hull Intersection */
85 } 139 /* ========================================= */
86 prev = curr; 140 pair<int,int> find_crossing_edge(Point& a, Point& b, vector<Point>& ch, int start, int
87 } end) {
88 return wn != 0; // non-zero :) 141 int o_ref = orientation(a, b, ch[start]);
89 } 142 int n = ch.size();
90 143 int l = start, r = start + ((end - start + n) % n);
91 /* EvenOdd Rule (ray casting - crossing number) */ 144 while (l < r) {
92 bool inPolygon_evenodd(Point p, vector<Point>& pts) { 145 int m = (l+r) >> 1;
93 int cn = 0; // crossing number 146 if (orientation(a, b, ch[m % n]) != o_ref) r = m;
94 Point prev = pts.back(); 147 else l = m+1;
95 rep (i, 0, (int)pts.size() - 1) { 148 }
96 Point curr = pts[i]; 149 return {(l-1+n) % n, l%n};
97 if (((prev.y <= p.y) && (p.y < curr.y)) // upward crossing 150 }
98 || ((prev.y > p.y) && (p.y >= curr.y))) { // downward crossing 151 void find_segment_convexhull_intersection(Point& a, Point& b, vector<Point>& ch) {
99 // check intersect’s x-coordinate to the right of p 152 // find rightmost and leftmost points in convex hull wrt vector a -> b
100 double t = (p.y - prev.y) / (curr.y - prev.y); 153 int i1 = extreme_point_index(a, b, ch);
101 if (p.x < prev.x + t * (curr.x - prev.x)) 154 int i2 = extreme_point_index(b, a, ch);
102 ++cn; 155 // make sure the extremes are not to the same side
103 } 156 int o1 = orientation(a, b, ch[i1]);
104 prev = curr; 157 int o2 = orientation(a, b, ch[i2]);
105 } 158 if (o1 == o2) return; // all points are to the right (left) of a -> b (no
106 return (cn & 1); // odd -> in, even -> out intersection)
Pablo Messina’s ICPC Notebook 9 GEOMETRY - 9.4 Trigonometry Página 36 de 40
159 // find 2 edges in the convex hull intersected by the straight line <- a - b -> 2 using namespace std;
160 pair<int,int> e1 = find_crossing_edge(a, b, ch, i1, i2); // binsearch from i1 to i2 3 #define rep(i,a,b) for(int i = a; i <= b; ++i)
ccw 4 #define invrep(i,b,a) for(int i = b; i >= a; --i)
161 pair<int,int> e2 = find_crossing_edge(a, b, ch, i2, i1); // binsearch from i2 to i1 5 typedef long long int ll;
ccw 6 // ----------------------------------------------
162 // find exact intersection points 7 // Convex Hull: Andrew’s Montone Chain Algorithm
163 double r1, s1, r2, s2; 8 // ----------------------------------------------
164 assert (find_line_line_intersection(a, b, ch[e1.first], ch[e1.second], r1, s1)); 9 struct Point {
165 assert (find_line_line_intersection(a, b, ch[e2.first], ch[e2.second], r2, s2)); 10 ll x, y;
166 // make sure intersections are significant and within line segment range 11 bool operator<(const Point& p) const {
167 if (r1 > 1.0 - EPS and r2 > 1.0 - EPS) return; // intersections above line segment 12 return x < p.x || (x == p.x && y < p.y);
168 if (r1 < EPS and r2 < EPS) return; // intersections below line segment 13 }
169 if (abs(r1 - r2) < EPS) return; // insignificant intersection in a single point 14 };
170 if (r1 > r2) swap(r1, r2), swap(e1, e2), swap(s1, s2); // make sure r1 < r2 15
171 // ** HERE DO WHATEVER YOU WANT WITH INTERSECTIONS FOUND 16 ll cross(Point& a, Point& b, Point& c) {
172 // 1) a + (b-a) * max(r1, 0) <--- first point of segment a -> b inside convex hull 17 ll dx0 = b.x - a.x, dy0 = b.y - a.y;
173 // if r1 < 0, point a is strictly inside the convex hull 18 ll dx1 = c.x - a.x, dy1 = c.y - a.y;
174 // 2) a + (b-a) * min(r2, 1) <--- last point of segment a -> b inside convex hull 19 return dx0 * dy1 - dx1 * dy0;
175 // if r2 > 1, point b is strictly inside the convex hull 20 }
176 cout << "(significant) intersection detected!\n"; 21
177 } 22 vector<Point> upper_hull(vector<Point>& P) {
23 // sort points lexicographically
9.4 Trigonometry 24 int n = P.size(), k = 0;
25 sort(P.begin(), P.end());
1 /* ================= */ 26 // build upper hull
2 /* Angle of a vector */ 27 vector<Point> uh(n);
3 /* ================= */ 28 invrep (i, n-1, 0) {
4 const double PI = acos(-1); 29 while (k >= 2 && cross(uh[k-2], uh[k-1], P[i]) <= 0) k--;
5 const double _2PI = 2 * PI; 30 uh[k++] = P[i];
6 31 }
7 double correct_angle(double angle) { // to ensure 0 <= angle <= 2PI 32 uh.resize(k);
8 while (angle < 0) angle += _2PI; 33 return uh;
9 while (angle > _2PI) angle -= _2PI; 34 }
10 return angle; 35

11 } 36 vector<Point> lower_hull(vector<Point>& P) {
12 double angle(double x, double y) { 37 // sort points lexicographically
13 // atan2 by itself returns an angle in range [-PI, PI] 38 int n = P.size(), k = 0;
14 // no need to "correct it" if that range is ok for you 39 sort(P.begin(), P.end());
15 return correct_angle(atan2(y, x)); 40 // collect lower hull
16 } 41 vector<Point> lh(n);
17 42 rep (i, 0, n-1) {
18 /* ============== */ 43 while (k >= 2 && cross(lh[k-2], lh[k-1], P[i]) <= 0) k--;
19 /* Cosine Theorem */ 44 lh[k++] = P[i];
20 /* ============== */ 45 }
21 // Given triangle with sides a, b and c, returns the angle opposed to side a. 46 lh.resize(k);
22 // a^2 = b^2 + c^2 - 2*b*c*cos(alpha) 47 return lh;
23 // => alpha = acos((b^2 + c^2 - a^2) /(2*b*c)) 48 }
24 double get_angle(double a, double b, double c) { 49

25 return acos((b*b + c*c - a*a)/(2*b*c)); 50 vector<Point> convex_hull(vector<Point>& P) {


26 } 51 int n = P.size(), k = 0;
52 // set initial capacity
9.5 Convex Hull 53 vector<Point> H(2*n);
54 // sort points lexicographically
1 #include <bits/stdc++.h> 55 sort(P.begin(), P.end());
Pablo Messina’s ICPC Notebook 10 STRINGS - 9.6 Green’s Theorem Página 37 de 40
56 // build lower hull 1 // ========================================================
57 for (int i = 0; i < n; ++i) { 2 // Suffix Array Construction : Prefix Doubling + Radix Sort
58 while (k >= 2 && cross(H[k-2], H[k-1], P[i]) <= 0) k--; 3 // ========================================================
59 H[k++] = P[i]; 4 // Complexity: O(N*log(N))
60 } 5 // references: https://www.cs.helsinki.fi/u/tpkarkka/opetus/10s/spa/lecture11.pdf
61 // build upper hull 6 // https://youtu.be/_TUeAdu-U_k
62 for (int i = n-2, t = k+1; i >= 0; i--) { 7 #include <bits/stdc++.h>
63 while (k >= t && cross(H[k-2], H[k-1], P[i]) <= 0) k--; 8 #define rep(i,a,b) for(int i = a; i <= b; ++i)
64 H[k++] = P[i]; 9 #define invrep(i,b,a) for(int i = b; i >= a; --i)
65 } 10 using namespace std;
66 // remove extra space 11
67 H.resize(k-1); 12 // - the input to the suffix array must be a vector of ints
68 return H; 13 // - all values in the vector must be >= 1 (because 0 is used
69 } 14 // as a special value internally)
15 struct SuffixArray {
9.6 Green’s Theorem 16 int n;
17 vector<int> counts, rank, rank_tmp, sa, sa_tmp;
1 #include <bits/stdc++.h> 18 vector<int> lcp; // optional: only if lcp is needed
2 using namespace std; 19 inline int get_rank(int i) { return i < n ? rank[i]: 0; }
3 typedef long long int ll; 20 void counting_sort(int maxv, int k) {
4
21 counts.assign(maxv+1, 0);
5 struct Point { double x, y; }; 22 rep(i,0,n-1) counts[get_rank(i+k)]++;
6
23 rep(i,1,maxv) counts[i] += counts[i-1];
7 // Computes the line integral of the vector field <0,x> over the arc of the circle with 24 invrep(i,n-1,0) sa_tmp[--counts[get_rank(sa[i]+k)]] = sa[i];
radius ’r’ 25 sa.swap(sa_tmp);
8 // and x-coordinate ’x’ from angle ’a’ to angle ’b’. The ’y’ goes away in the integral so 26 }
it 27 void compute_sa(vector<int>& s) {
9 // it doesn’t matter. 28 rep(i,0,n-1) sa[i] = i;
10 // This can be done using a parameterization of the arc in polar coordinates: 29 sort(sa.begin(), sa.end(), [&s](int i, int j) { return s[i] < s[j]; });
11 // x(t) = x + r * cos(t) 30 int r = rank[sa[0]] = 1;
12 // y(t) = y + r * sin(t) 31 rep(i,1,n-1) rank[sa[i]] = (s[sa[i]] != s[sa[i-1]]) ? ++r : r;
13 // a <= t <= b 32 for (int h=1; h < n and r < n; h <<= 1) {
14 // The final integral can be seen here: 33 counting_sort(r, h);
15 // https://www.wolframalpha.com/input/?i=integral((x+%2B+r*cos(t))+*+derivative(y+%2B+r* 34 counting_sort(r, 0);
sin(t))+*+dt,+t%3Da..b) 35 r = rank_tmp[sa[0]] = 1;
16 double arc_integral(double x, double r, double a, double b) { 36 rep(i,1,n-1) {
17 return x * r * (sin(b) - sin(a)) + r * r * 0.5 * (0.5 * (sin(2*b) - sin(2*a)) + b - a 37 if (rank[sa[i]] != rank[sa[i-1]] or
); 38 get_rank(sa[i]+h) != get_rank(sa[i-1]+h)) ++r;
18 } 39 rank_tmp[sa[i]] = r;
19
40 }
20 // Computes the line integral of the vector field <0, x> over the directed segment a -> b 41 rank.swap(rank_tmp);
21 // This can be done using the parameterization: 42 }
22 // x(t) = a.x + (b.x - a.x) * t 43 }
23 // y(t) = a.y + (b.y - a.y) * t 44 // LCP construction in O(N) using Kasai’s algorithm
24 // 0 <= t <= 1 45 // reference: https://codeforces.com/blog/entry/12796?#comment-175287
25 double segment_integral(Point& a, Point& b) { 46 void compute_lcp(vector<int>& s) { // optional: only if lcp array is needed
26 return 0.5 * (a.x + b.x) * (b.y - a.y); 47 lcp.assign(n, 0);
27 } 48 int k = 0;
49 rep(i,0,n-1) {
50 int r = rank[i]-1;
10 Strings 51 if (r == n-1) { k = 0; continue; }
52 int j = sa[r+1];
10.1 Suffix Array 53 while (i+k<n and j+k<n and s[i+k] == s[j+k]) k++;
54 lcp[r] = k;
Pablo Messina’s ICPC Notebook 10 STRINGS - 10.2 Trie Página 38 de 40
55 if (k) k--; 30 int size() { return g.size(); }
56 } 31 };
57 } 32
58 SuffixArray(vector<int>& s) { 33 // example of usage
59 n = s.size(); 34 int main() {
60 rank.resize(n); rank_tmp.resize(n); 35 Trie trie(26);
61 sa.resize(n); sa_tmp.resize(n); 36 for (string s : {"hell", "hello", "hellyeah", "helpzzzz", "abcdefg"}) {
62 compute_sa(s); 37 cout << "inserting " << s << ’\n’;
63 compute_lcp(s); // optional: only if lcp array is needed 38 trie.insert(s);
64 } 39 cout << "\ttrie size = " << trie.size() << ’\n’;
65 }; 40 }
66 41 return 0;
67 int main() { // how to use 42 }
68 string test; cin >> test;
69 vector<int> s; 10.3 Rolling Hashing
70 for (char c : test) s.push_back(c);
71 SuffixArray sa(s); 1 #include <bits/stdc++.h>
72 for (int i : sa.sa) cout << i << ":\t" << test.substr(i) << ’\n’; 2 using namespace std;
73 rep (i, 0, s.size() - 1) { 3 #define rep(i,a,b) for(int i = a; i <= b; ++i)
74 printf("LCP between %d and %d is %d\n", i, i+1, sa.lcp[i]); 4 typedef unsigned long long int ull;
75 } 5 const int MAXLEN = 1e6;
76 } 6
7 // -----------------------------
10.2 Trie 8 // Rolling Hashing: single hash
9
1 #include <bits/stdc++.h> 10 struct RH_single { // rolling hashing
2 using namespace std; 11 static const ull B = 131; // base
3 struct Trie { 12 static const ull P = 1e9 + 21; // prime
4 vector<vector<int>> g; 13 static ull pow[MAXLEN];
5 vector<int> count; 14 static ull add(ull x, ull y) { return (x + y) % P; }
6 int vocab; 15 static ull mul(ull x, ull y) { return (x * y) % P; }
7 Trie(int vocab, int maxdepth = 10000) : vocab(vocab) { 16 static void init() {
8 g.reserve(maxdepth); 17 pow[0] = 1;
9 g.emplace_back(vocab, -1); 18 rep(i, 1, MAXLEN-1) pow[i] = mul(B, pow[i-1]);
10 count.reserve(maxdepth); 19 }
11 count.push_back(0); 20 vector<ull> h;
12 } 21 int len;
13 int move_to(int u, int c) { 22 void init(vector<int>& s) {
14 assert (0 <= c and c < vocab); 23 for (int x : s) assert (x >= 1); // DEBUGGING
15 int& v = g[u][c]; 24 len = s.size();
16 if (v == -1) { 25 h.resize(len);
17 v = g.size(); 26 h[0] = s[0];
18 g.emplace_back(vocab, -1); 27 rep(i,1,len-1) h[i] = add(mul(h[i-1], B), s[i]);
19 count.push_back(0); 28 }
20 } 29 RH_single(vector<int>& s) { init(s); } // from vector<int>
21 count[v]++; 30 RH_single(string& s, char ref) { // from string
22 return v; 31 vector<int> tmp; for(char c : s) tmp.push_back(c - ref + 1);
23 } 32 init(tmp);
24 void insert(const string& s, char ref = ’a’) { // insert string 33 }
25 int u = 0; for (char c : s) u = move_to(u, c - ref); 34 ull hash(int i, int j) {
26 } 35 if (i == 0) return h[j];
27 void insert(vector<int>& s) { // insert vector<int> 36 return add(h[j], P - mul(h[i-1], pow[j - i + 1]));
28 int u = 0; for (int c : s) u = move_to(u, c); 37 }
29 } 38 ull hash() { return h[len-1]; }
Pablo Messina’s ICPC Notebook 10 STRINGS - 10.4 KMP (Knuth Morris Pratt) Página 39 de 40
39 }; 93 ull h1 = rh.hash(l1, r1);
40 ull RH_single::pow[MAXLEN]; // necessary for the code to compile 94 ull h2 = rh.hash(l2, r2);
41 95 string s1 = s.substr(l1, r1-l1+1);
42 // -------------------------------------------- 96 string s2 = s.substr(l2, r2-l2+1);
43 // Rolling Hashing: double hash (extra safety) 97 printf("Strings s1=%s and s2=%s are %s\n", s1.c_str(), s2.c_str(),
44 98 h1 == h2 ? "EQUAL" : "DISTINCT");
45 struct RH_double { // rolling hashing 99 }
46 static const ull B = 131; // base 100 }
47 static const ull P[2]; // primes
48 static ull pow[2][MAXLEN]; 10.4 KMP (Knuth Morris Pratt)
49 static ull add(ull x, ull y, int a) { return (x + y) % P[a]; }
50 static ull mul(ull x, ull y, int a) { return (x * y) % P[a]; } 1 #include <bits/stdc++.h>
51 static void init(int a) { 2 using namespace std;
52 pow[a][0] = 1; 3 #define rep(i,a,b) for(int i=a; i<=b; ++i)
53 rep(i, 1, MAXLEN-1) pow[a][i] = mul(B, pow[a][i-1], a); 4
54 } 5 // Build longest proper prefix/suffix array (lps) for pattern
55 static void init() { init(0); init(1); } 6 // lps[i] = length of the longest proper prefix which is also suffix in pattern[0 .. i]
56 vector<ull> h[2]; 7 void init_lps(string& pattern, int lps[]) {
57 int len; 8 int n = pattern.size();
58 void init(vector<int>& s) { 9 lps[0] = 0; // base case: no proper prefix/suffix for pattern[0 .. 0] (length 1)
59 for (int x : s) assert (x >= 1); // DEBUGGING 10 rep(j, 1, n-1) { // for each pattern[0 .. j]
60 len = s.size(); 11 int i = lps[j-1]; // i points to the char next to lps of previous iteration
61 rep(a,0,1) { 12 while (pattern[i] != pattern[j] and i > 0) i = lps[i-1];
62 h[a].resize(len); 13 lps[j] = pattern[i] == pattern[j] ? i+1 : 0;
63 h[a][0] = s[0]; 14 }
64 rep(i,1,len-1) h[a][i] = add(mul(h[a][i-1], B, a), s[i], a); 15 }
65 } 16
66 } 17 // Count number of matches of pattern string in target string using KMP algorithm
67 RH_double(vector<int>& s) { init(s); } // from vector<int> 18 int count_matches(string& pattern, string& target) {
68 RH_double(string& s, char ref) { // from string 19 int n = pattern.size(), m = target.size();
69 vector<int> tmp; for (char c : s) tmp.push_back(c - ref + 1); 20 int lps[n];
70 init(tmp); 21 init_lps(pattern, lps); // build lps array
71 } 22 int matches = 0;
72 ull hash(int i, int j, int a) { 23 int i = 0; // i tracks current char in pattern to compare
73 if (i == 0) return h[a][j]; 24 rep(j, 0, m-1) { // j tracks each char in target to compare
74 return add(h[a][j], P[a] - mul(h[a][i-1], pow[a][j-i+1], a), a); 25 // try to keep prefix before i as long as possible while ensuring i matches j
75 } 26 while (pattern[i] != target[j] and i > 0) i = lps[i-1];
76 ull hash(int i, int j) { 27 if (pattern[i] == target[j]) {
77 return hash(i,j,0) << 32 | hash(i,j,1); 28 if (++i == n) { // we matched the whole pattern
78 } 29 i = lps[n-1]; // shift the pattern so that the longest proper prefix/
79 ull hash() { return hash(0, len-1); } suffix pair is aligned
80 }; 30 matches++;
81 // these lines are necessary for the code to compile 31 }
82 const ull RH_double::P[2] = {(ull)1e9+21, (ull)1e9+9}; 32 }
83 ull RH_double::pow[2][MAXLEN]; 33 }
84 34 return matches;
85 // ----- usage & testing 35 }
86 int main() { 36
87 RH_double::init(); 37 int main() { // usage
88 while (true) { 38 string target, pattern;
89 string s; cin >> s; 39 while (true) {
90 int l1, r1, l2, r2; cin >> l1 >> r1 >> l2 >> r2; 40 cin >> target >> pattern;
91 char cmin = *min_element(s.begin(), s.end()); 41 cout << count_matches(pattern, target) << " matches\n";
92 RH_double rh(s, cmin); 42 }
Pablo Messina’s ICPC Notebook 10 STRINGS - 10.5 Shortest Repeating Cycle Página 40 de 40
43 return 0;
44 }

10.5 Shortest Repeating Cycle


1 #include <bits/stdc++.h>
2 using namespace std;
3
4 int shortest_repeating_cycle(string& seq) {
5 // KMP : lps step
6 int n = seq.size();
7 int lps[n];
8 lps[0] = 0;
9 int i = 0, j = 1;
10 while (j < n) {
11 while (i > 0 and seq[i] != seq[j])
12 i = lps[i-1];
13 if (seq[i] == seq[j])
14 lps[j] = ++i;
15 else
16 lps[j] = 0;
17 j++;
18 }
19 int len = n - lps[n-1];
20 return (n % len) ? n : len;
21 }
22
23 // test
24 int main() {
25 string line; cin >> line;
26 int cycle = shortest_repeating_cycle(line);
27 cout << line.substr(0, cycle) << endl;
28 return 0;
29 }

You might also like