├── .gitignore ├── .travis.yml ├── README.md ├── code ├── AVLtree.hpp ├── BinaryHeap.hpp ├── BridgeTree.hpp ├── DisjointSet.hpp ├── DynamicProgramming.hpp ├── FastFourier.hpp ├── FlowAlgorithms.hpp ├── Geometry.hpp ├── Graphs.hpp ├── HuffmanTree.hpp ├── MergeSortTree.hpp ├── MinMaxHeap.hpp ├── NumberTheory.hpp ├── PersistentSegTree.hpp ├── SearchString.hpp ├── SegmentTree.hpp ├── Tree.hpp └── Trie.hpp ├── img ├── heavy-light-decomposition.png └── iiit-logo.jpeg ├── notebook.out ├── notebook.pdf ├── notebook.tex ├── others ├── anurudh.pdf ├── berkeley.pdf ├── khattar.pdf └── stanford.pdf ├── ques ├── adhoc │ ├── 0339D.cpp │ └── p2121.cpp ├── heaps │ ├── ANUMLA.cpp │ ├── IPCTRAIN.cpp │ ├── KSUBSUM.cpp │ ├── MOSTDIST.cpp │ └── findingtherunningmedian.cpp ├── palindromes │ └── BINPALIN.cpp ├── rare │ └── ADAMTR.cpp ├── segtree │ └── 380C.cpp └── stacks │ ├── 0005C.cpp │ ├── 0281D.cpp │ ├── 0343B.cpp │ ├── andxoror.cpp │ └── poisonousplants.cpp ├── ref ├── DisjointSets.cpp ├── DynamicProgramming.cpp ├── FastFourier.cpp ├── FlowAlgorithms.cpp ├── Geometry.cpp ├── GraphAlgorithms.cpp ├── MathematicsTheory.tex ├── MatrixTools.cpp ├── MergeSortTree.cpp ├── Miscelleneous.cpp ├── MobiusSieve.cpp ├── PalindromicTree.cpp ├── SegmentTree.cpp ├── StonglyConnected.cpp ├── StringAlgorithms.cpp ├── TreapsIntervals.cpp ├── TreesCentroids.cpp ├── _team_reference.pdf ├── generate.sh ├── team.pdf └── template.hpp ├── template.json ├── test.sh ├── tests ├── BellmanFord.test.cpp ├── Dijkstra.test.cpp ├── Dinics.test.cpp ├── DisjointSet.test.cpp ├── FloydWarshall.test.cpp ├── HopkroftKarp.test.cpp ├── PushRelabel.test.cpp └── tests_status.md └── tex ├── _strategysheet.tex ├── dynamicprogramming.tex ├── flows.tex ├── gametheory.tex ├── graphstrees.tex ├── mathematicaltools.tex ├── probability.tex ├── rangequeries.tex └── stackqueueheap.tex /.gitignore: -------------------------------------------------------------------------------- 1 | # VScode editor directory 2 | .vscode/ 3 | 4 | # Keeping away the CLion Files 5 | code/.idea/ 6 | ques/.idea/ 7 | code/cmake-build-debug/ 8 | ques/cmake-build-debug/ 9 | .idea 10 | 11 | # The LaTeX output files 12 | notebook.aux 13 | notebook.fls 14 | notebook.log 15 | notebook.synctex.gz 16 | notebook.fdb_latexmk 17 | 18 | # online judge tool files 19 | cache/* 20 | 21 | # Compiled C++ Binaries 22 | *.test 23 | *.out 24 | *.o -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - clang 4 | - gcc 5 | dist: bionic 6 | addons: 7 | apt: 8 | packages: 9 | - python3 10 | - python3-pip 11 | - python3-setuptools 12 | 13 | before_install: 14 | - pip3 install -U setuptools 15 | - pip3 install -U online-judge-tools=='9.*' 16 | script: 17 | - bash test.sh 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AlgorithmsNotebook 2 | 3 | ![Build Status](https://img.shields.io/travis/AnimeshSinha1309/AlgorithmsNotebook/master.svg) 4 | 5 | The team notebook to keep all template code and notes in. 6 | 7 | ## Notebook Contents 8 | 9 | ### Data Structures 10 | 11 | The following data structures are a part of the notebook: 12 | * AVL Tree 13 | * Binary Heap 14 | * Disjoint Set Union Find 15 | * Convex Hull Trick to Dynamic Programming 16 | * Segment Tree - Point Update Range Query 17 | * Segment Tree - Range Update Point Query 18 | * Segment Tree - Lazy 19 | * Segment Tree - Implicit with Range Query 20 | * Segment Tree - Implicit with Point Query 21 | * Tree (with LCA) 22 | * Graphs (Bellman Ford, Ford Fulkerson, Dijkstra, Prims, Floyd Warshall, Components) 23 | 24 | ### Algorithms 25 | 26 | The following algorithms are a part of the notebook: 27 | * Knuth Morris Pratt - String Search 28 | * Centroid Decomposition 29 | * Heavy Light Decomposition 30 | * Huffman Tree Encoding 31 | * Kosaraju's algorithms for Strongly Connected Components 32 | -------------------------------------------------------------------------------- /code/AVLtree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_AVL_TREE_H 2 | #define CODE_AVL_TREE_H 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | template 10 | class AVLTree { 11 | struct Node { 12 | Type data; 13 | Node *left, *right, *parent; 14 | int height; 15 | int subtree_size; 16 | }; 17 | 18 | private: 19 | Node *root = nullptr; 20 | 21 | Node *__insert_node(Node *T, Type x) { 22 | if (T == nullptr) { 23 | T = new Node; 24 | T->data = x; 25 | T->left = nullptr; 26 | T->right = nullptr; 27 | } else if (x > T->data) { 28 | T->right = __insert_node(T->right, x); 29 | if (__height_difference(T) == -2) 30 | T = (x > T->right->data) ? __insert_right_right(T) 31 | : __insert_right_left(T); 32 | } else if (x < T->data) { 33 | T->left = __insert_node(T->left, x); 34 | if (__height_difference(T) == 2) 35 | T = (x < T->left->data) ? insert_left_left(T) 36 | : __insert_left_right(T); 37 | } 38 | T->height = __height(T); 39 | T->subtree_size = __subtree_size(T); 40 | return (T); 41 | } 42 | 43 | Node *__delete_node(Node *T, Type x) { 44 | Node *p; 45 | if (T == nullptr) { // Delete nothing 46 | return nullptr; 47 | } else if (x > T->data) { // Go to the right to find entity to delete 48 | // and balance 49 | T->right = __delete_node(T->right, x); 50 | if (__height_difference(T) == 2) 51 | T = (__height_difference(T->left) >= 0) 52 | ? insert_left_left(T) 53 | : __insert_left_right(T); 54 | } else if (x < T->data) { // Go to the left to find entity to delete 55 | // and balance 56 | T->left = __delete_node(T->left, x); 57 | if (__height_difference(T) == -2) 58 | T = (__height_difference(T->right) <= 0) 59 | ? __insert_right_right(T) 60 | : __insert_right_left(T); 61 | } else { // Delete the actual node 62 | if (T->right != nullptr) { 63 | p = T->right; 64 | while (p->left != nullptr) 65 | p = p->left; 66 | T->data = p->data; 67 | T->right = __delete_node(T->right, p->data); 68 | if (__height_difference(T) == 2) 69 | T = (__height_difference(T->left) >= 0) 70 | ? insert_left_left(T) 71 | : __insert_left_right(T); 72 | } else 73 | return (T->left); 74 | } 75 | T->height = __height(T); 76 | T->subtree_size = __subtree_size(T); 77 | return (T); 78 | } 79 | 80 | Node *__search_node(Node *T, Type x) { 81 | if (T == nullptr || T->data == x) { 82 | return T; 83 | } else if (x < T->data) { 84 | return __search_node(T->left, x); 85 | } else if (x > T->data) { 86 | return __search_node(T->right, x); 87 | } 88 | } 89 | unsigned long __count_lt(Node *T, Type x) { 90 | if (T == nullptr) { 91 | return 0; 92 | } else if (x <= T->data) { 93 | return __count_lt(T->left, x); 94 | } else if (x > T->data) { 95 | return __count_lt(T->right, x) + __subtree_size(T->left) + 1; 96 | } 97 | return 0; 98 | } 99 | unsigned long __count_gt(Node *T, Type x) { 100 | if (T == nullptr) { 101 | return 0; 102 | } else if (x < T->data) { 103 | return __count_gt(T->left, x) + __subtree_size(T->right) + 1; 104 | } else if (x >= T->data) { 105 | return __count_gt(T->right, x); 106 | } 107 | return 0; 108 | } 109 | Node *__search_quantile(Node *T, unsigned long count) { 110 | if (T == nullptr || count == 1) { 111 | return T; 112 | } else if (count < __subtree_size(T->left)) { 113 | return __search_quantile(T->left, count); 114 | } else if (count == __subtree_size(T->left)) { 115 | return T; 116 | } else { 117 | return __search_quantile(T->right, 118 | count - __subtree_size(T->left) - 1); 119 | } 120 | } 121 | 122 | int __height(Node *T) { 123 | int left_height, right_height; 124 | if (T == nullptr) 125 | return (0); 126 | left_height = (T->left == nullptr) ? 0 : 1 + T->left->height; 127 | right_height = (T->right == nullptr) ? 0 : 1 + T->right->height; 128 | return max(left_height, right_height); 129 | } 130 | int __subtree_size(Node *T) { 131 | int left_size, right_size; 132 | if (T == nullptr) 133 | return (0); 134 | left_size = (T->left == nullptr) ? 0 : T->left->subtree_size; 135 | right_size = (T->right == nullptr) ? 0 : T->right->subtree_size; 136 | return left_size + right_size + 1; 137 | } 138 | 139 | Node *__rotate_right(Node *x) { 140 | Node *y; 141 | y = x->left; 142 | x->left = y->right; 143 | y->right = x; 144 | x->height = __height(x); 145 | y->height = __height(y); 146 | x->subtree_size = __subtree_size(x); 147 | y->subtree_size = __subtree_size(y); 148 | return (y); 149 | } 150 | 151 | Node *__rotate_left(Node *x) { 152 | Node *y; 153 | y = x->right; 154 | x->right = y->left; 155 | y->left = x; 156 | x->height = __height(x); 157 | y->height = __height(y); 158 | x->subtree_size = __subtree_size(x); 159 | y->subtree_size = __subtree_size(y); 160 | return (y); 161 | } 162 | 163 | Node *__insert_right_right(Node *T) { 164 | T = __rotate_left(T); 165 | return (T); 166 | } 167 | Node *insert_left_left(Node *T) { 168 | T = __rotate_right(T); 169 | return (T); 170 | } 171 | Node *__insert_left_right(Node *T) { 172 | T->left = __rotate_left(T->left); 173 | T = __rotate_right(T); 174 | return (T); 175 | } 176 | Node *__insert_right_left(Node *T) { 177 | T->right = __rotate_right(T->right); 178 | T = __rotate_left(T); 179 | return (T); 180 | } 181 | 182 | int __height_difference(Node *T) { 183 | int lh, rh; 184 | if (T == nullptr) 185 | return (0); 186 | lh = (T->left == nullptr) ? 0 : 1 + T->left->height; 187 | rh = (T->right == nullptr) ? 0 : 1 + T->right->height; 188 | return (lh - rh); 189 | } 190 | 191 | public: 192 | AVLTree() { 193 | root = nullptr; 194 | } 195 | explicit AVLTree(vector data) { 196 | root = nullptr; 197 | for (auto el : data) 198 | root = __insert_node(root, el); 199 | } 200 | 201 | void in_order_traversal(Node *T) { 202 | if (T != nullptr) { 203 | in_order_traversal(T->left); 204 | cout << T->data << " "; 205 | in_order_traversal(T->right); 206 | } 207 | } 208 | void print() { 209 | in_order_traversal(root); 210 | } 211 | 212 | void insert(Type x) { 213 | root = __insert_node(root, x); 214 | } 215 | void erase(Type x) { 216 | root = __delete_node(root, x); 217 | } 218 | Node *search(Type x) { 219 | return __search_node(root, x); 220 | } 221 | 222 | unsigned long count_lt(Type x) { 223 | return __count_lt(root, x); 224 | } 225 | unsigned long count_gt(Type x) { 226 | return __count_gt(root, x); 227 | } 228 | unsigned long count_eq(Type x) { 229 | return (root != nullptr ? root->subtree_size : 0) - 230 | __count_lt(root, x) - __count_gt(root, x); 231 | } 232 | unsigned long count_le(Type x) { 233 | return (root != nullptr ? root->subtree_size : 0) - __count_gt(root, x); 234 | } 235 | unsigned long count_ge(Type x) { 236 | return (root != nullptr ? root->subtree_size : 0) - __count_lt(root, x); 237 | } 238 | Node *search_quantile(unsigned long index) { 239 | return __search_quantile(root, index); 240 | } 241 | 242 | void size() { 243 | return root->subtree_size; 244 | } 245 | }; 246 | 247 | #endif // CODE_AVL_TREE_H -------------------------------------------------------------------------------- /code/BinaryHeap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_BINARY_HEAP_H 2 | #define CODE_BINARY_HEAP_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | template 7 | class BinaryHeap { 8 | protected: 9 | function comp; 10 | 11 | vector data; 12 | void siftDown(unsigned long pos) { 13 | if (pos >= data.size()) 14 | return; 15 | bool hasLChild = lChild(pos) < data.size(), 16 | hasRChild = rChild(pos) < data.size(); 17 | if ((hasLChild && comp(data[lChild(pos)], data[pos])) || 18 | (hasRChild && comp(data[rChild(pos)], data[pos]))) { 19 | if (!hasRChild || 20 | (hasLChild && comp(data[lChild(pos)], data[rChild(pos)]))) { 21 | swap(pos, lChild(pos)); 22 | siftDown(lChild(pos)); 23 | } else { 24 | swap(pos, rChild(pos)); 25 | siftDown(rChild(pos)); 26 | } 27 | } 28 | } 29 | void siftUp(unsigned long pos) { 30 | if (pos == 0) 31 | return; // This is the Root Element 32 | if (comp(data[pos], data[parent(pos)])) { 33 | swap(pos, parent(pos)); 34 | siftUp(parent(pos)); 35 | } 36 | } 37 | inline unsigned long parent(unsigned long val) { 38 | return (val - 1) / 2; 39 | } 40 | inline unsigned long lChild(unsigned long val) { 41 | return 2 * val + 1; 42 | } 43 | inline unsigned long rChild(unsigned long val) { 44 | return 2 * val + 2; 45 | } 46 | void swap(unsigned long x, unsigned long y) { 47 | data[x] ^= data[y]; 48 | data[y] ^= data[x]; 49 | data[x] ^= data[y]; 50 | } 51 | 52 | public: 53 | explicit BinaryHeap(const vector &list, 54 | function heapComparator = less<>()) { 55 | comp = heapComparator; 56 | for (auto i : list) 57 | data.push_back(i); 58 | for (long i = data.size() - 1; i >= 0; i--) { 59 | siftDown((unsigned)i); 60 | } 61 | } 62 | explicit BinaryHeap(function heapComparator = less<>()) { 63 | comp = heapComparator; 64 | data = vector(); 65 | } 66 | BinaryHeap(const BinaryHeap &heap) { 67 | comp = heap.comp; 68 | for (auto val : heap.data) 69 | data.push_back(val); 70 | } 71 | void insert(int val) { 72 | data.push_back(val); 73 | siftUp(data.size() - 1); 74 | } 75 | void remove(unsigned long pos) { 76 | swap(data.size() - 1, pos); 77 | data.pop_back(); 78 | siftUp(pos); 79 | siftDown(pos); 80 | } 81 | Type top() { 82 | return data[0]; 83 | } 84 | vector sort() { 85 | vector result; 86 | BinaryHeap copy(*this); 87 | while (!copy.data.empty()) { 88 | result.push_back(copy.top()); 89 | copy.remove(0); 90 | } 91 | return result; 92 | } 93 | }; 94 | 95 | #endif // CODE_BINARY_HEAP_H 96 | -------------------------------------------------------------------------------- /code/BridgeTree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_FLOW_ALGORITHMS_H 2 | #define CODE_FLOW_ALGORITHMS_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | class BridgeTree { 7 | map, int> bridge; 8 | vector depth; 9 | vector> gr, Tree; 10 | vector vst; 11 | int n, Nodes; 12 | 13 | public: 14 | BridgeTree(const vector> &Gr) { 15 | gr = Gr; 16 | n = gr.size(); 17 | depth.assign(n, 0); 18 | vst.assign(n, false); 19 | Nodes = 1; 20 | } 21 | int dfs(int u, int pa, vector &vst, int d) { 22 | vst[u] = true; 23 | depth[u] = d; 24 | int mx = d; 25 | for (auto it : gr[u]) { 26 | if (!vst[it]) { 27 | int mx1 = dfs(it, u, vst, d + 1); 28 | mx = min(mx, mx1); 29 | if (mx1 > d) { 30 | bridge[minmax(u, it)] = 1; 31 | } 32 | } else if (it != pa) { 33 | mx = min(mx, depth[it]); 34 | } 35 | } 36 | return mx; 37 | } 38 | void dfs2(int u, vector &vst, int node) { 39 | vst[u] = true; 40 | for (auto it : gr[u]) { 41 | if (!vst[it]) { 42 | int v1 = node; 43 | if (bridge.count(minmax(u, it))) { 44 | v1 = Nodes++; 45 | Tree[node].pb(v1); 46 | Tree[v1].pb(node); 47 | } 48 | dfs2(it, vst, v1); 49 | } 50 | } 51 | } 52 | vector> tree() { 53 | dfs(0, -1, vst, 0); 54 | fill(all(vst), false); 55 | Tree.resize(sz(bridge) + 1); 56 | dfs2(0, vst, 0); 57 | return Tree; 58 | } 59 | }; 60 | 61 | 62 | #endif // CODE_FLOW_ALGORITHMS_H -------------------------------------------------------------------------------- /code/DisjointSet.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_DISJOINTSETUNIONFIND_H 2 | #define CODE_DISJOINTSETUNIONFIND_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | struct DisjointSetTree { 7 | ll comp_count; 8 | vector parent, comp_size; 9 | set roots; 10 | 11 | DisjointSetTree(int n) { 12 | comp_count = n; 13 | parent.resize(n); 14 | comp_size.resize(n, 1); 15 | iota(parent.begin(), parent.end(), 0); 16 | for (int i = 0; i < n; i++) { 17 | roots.insert(i); 18 | } 19 | } 20 | 21 | int find(int u) { 22 | if (parent[u] == u) 23 | return parent[u]; 24 | return parent[u] = find(parent[u]); 25 | } 26 | 27 | bool merge(int u, int v) { 28 | u = find(u), v = find(v); 29 | if (u == v) 30 | return false; 31 | parent[u] = v; 32 | comp_size[v] += comp_size[u]; 33 | comp_size[u] = 0; 34 | roots.erase(u); 35 | comp_count--; 36 | return true; 37 | } 38 | }; 39 | 40 | class DynamicConnectivity { 41 | void __dfs(int v, int l, int r, vector& res) { 42 | long long last_ans = answer; 43 | int state = save_ptr; 44 | for (auto query : tree[v]) 45 | merge(query); 46 | if (l == r - 1) 47 | res[l] = answer; 48 | else { 49 | int m = (l + r) / 2; 50 | __dfs(v * 2 + 1, l, m, res); 51 | __dfs(v * 2 + 2, m, r, res); 52 | } 53 | while (save_ptr != state) 54 | rollback(); 55 | answer = last_ans; 56 | }; 57 | 58 | public: 59 | int size_nodes; 60 | int size_query; 61 | 62 | struct Node { 63 | long long parent, comp_size = 1; 64 | }; 65 | long long answer = 0; 66 | vector data; 67 | vector saved_object; 68 | vector saved_value; 69 | int save_ptr = 0; 70 | 71 | struct Query { 72 | int u, v; 73 | Query(pair p = {0, 0}) { 74 | u = p.first, v = p.second; 75 | } 76 | }; 77 | vector> tree; 78 | 79 | DynamicConnectivity(int n = 600000, int q = 300000) { 80 | size_nodes = n; 81 | size_query = q; 82 | int tree_size = 1; 83 | while (tree_size < q) 84 | tree_size <<= 1; 85 | data = vector(n); 86 | tree = vector>(2 * tree_size); 87 | saved_object = vector(4 * q); 88 | saved_value = vector(4 * q); 89 | for (int i = 0; i < n; i++) { 90 | data[i].parent = i; 91 | } 92 | // Storing the initial answer 93 | answer = n; 94 | } 95 | 96 | void change(long long& x, long long y) { 97 | saved_object[save_ptr] = &x; 98 | saved_value[save_ptr] = x; 99 | x = y; 100 | save_ptr++; 101 | } 102 | 103 | void rollback() { 104 | save_ptr--; 105 | (*saved_object[save_ptr]) = saved_value[save_ptr]; 106 | } 107 | 108 | int find(int x) { 109 | if (data[x].parent == x) 110 | return x; 111 | return find(data[x].parent); 112 | } 113 | 114 | void merge(const Query& q) { 115 | int x = find(q.u); 116 | int y = find(q.v); 117 | if (x == y) 118 | return; 119 | if (data[x].comp_size < data[y].comp_size) 120 | swap(x, y); 121 | change(data[y].parent, x); 122 | change(data[x].comp_size, data[x].comp_size + data[y].comp_size); 123 | // Changing the Answer on query 124 | change(answer, answer - 1); 125 | } 126 | 127 | void add(int l, int r, Query edge, int node = 0, int x = 0, int y = -1) { 128 | if (y == -1) 129 | y = size_query; 130 | if (l >= r) 131 | return; 132 | if (l == x && r == y) 133 | tree[node].push_back(edge); 134 | else { 135 | int m = (x + y) / 2; 136 | add(l, min(r, m), edge, node * 2 + 1, x, m); 137 | add(max(m, l), r, edge, node * 2 + 2, m, y); 138 | } 139 | } 140 | 141 | vector solve(int v = 0, int l = 0, int r = -1) { 142 | if (r == -1) 143 | r = size_query; 144 | vector vec(size_query); 145 | if (size_query > 0) 146 | __dfs(v, l, r, vec); 147 | return vec; 148 | } 149 | 150 | DynamicConnectivity(int n, vector queries) 151 | : DynamicConnectivity(n, queries.size()) { 152 | map, int> last; 153 | for (int i = 0; i < size_query; i++) { 154 | pair p(queries[i].u, queries[i].v); 155 | if (last.count(p)) { 156 | add(last[p], i, queries[i]); 157 | last.erase(p); 158 | } else { 159 | last[p] = i; 160 | } 161 | } 162 | for (auto x : last) 163 | add(x.second, size_query, x.first); 164 | } 165 | }; 166 | 167 | #endif // CODE_DISJOINTSETUNIONFIND_H -------------------------------------------------------------------------------- /code/DynamicProgramming.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_DYNAMIC_PROGRAMMING_H 2 | #define CODE_DYNAMIC_PROGRAMMING_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | using namespace std; 11 | 12 | class LineContainer { 13 | private: 14 | struct Line { 15 | mutable long long slope, constt, p; 16 | bool operator<(const Line &o) const { 17 | return slope < o.slope; 18 | } 19 | bool operator<(long long x) const { 20 | return p < x; 21 | } 22 | }; 23 | 24 | multiset> lines; 25 | // (for doubles, use inf = 1/.0, div(a,b) = a/b) 26 | bool __is_max_query = false; 27 | const long long inf = LLONG_MAX; 28 | long long __div(long long a, long long b) { // floored division 29 | return a / b - ((a ^ b) < 0 && a % b); 30 | } 31 | bool __intersect(multiset::iterator x, multiset::iterator y) { 32 | if (y == lines.end()) { 33 | x->p = inf; 34 | return false; 35 | } 36 | if (x->slope == y->slope) 37 | x->p = x->constt > y->constt ? inf : -inf; 38 | else 39 | x->p = __div(y->constt - x->constt, x->slope - y->slope); 40 | return x->p >= y->p; 41 | } 42 | 43 | public: 44 | LineContainer(bool is_max = false) { 45 | this->__is_max_query = is_max; 46 | } 47 | void add(long long slope, long long constt) { 48 | if (!__is_max_query) { 49 | slope = -slope; 50 | constt = -constt; 51 | } 52 | auto z = lines.insert({slope, constt, 0}), y = z++, x = y; 53 | while (__intersect(y, z)) 54 | z = lines.erase(z); 55 | if (x != lines.begin() && __intersect(--x, y)) 56 | __intersect(x, y = lines.erase(y)); 57 | while ((y = x) != lines.begin() && (--x)->p >= y->p) 58 | __intersect(x, lines.erase(y)); 59 | } 60 | long long query(long long x) { 61 | assert(!lines.empty()); 62 | auto l = *lines.lower_bound(x); 63 | return (l.slope * x + l.constt) * (__is_max_query ? 1 : -1); 64 | } 65 | }; 66 | 67 | template 68 | vector dp_sumoversubsets(vector data) { 69 | int len = 0, n = 1; 70 | while (n < data.size()) 71 | len++, n *= 2; 72 | for (int i = 0; i < len; ++i) { 73 | for (int mask = 0; mask < n; ++mask) { 74 | if (mask & (1 << i)) 75 | data[mask] += data[mask ^ (1 << i)]; 76 | } 77 | } 78 | return dp; 79 | } 80 | 81 | #endif // CODE_DYNAMIC_PROGRAMMING_H -------------------------------------------------------------------------------- /code/FastFourier.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_FASTFOURIER_H 2 | #define CODE_FASTFOURIER_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | // use llround(a[i].real()) when printing FFT output 7 | 8 | const double PI = acos(-1); 9 | 10 | #ifdef IS_FFT 11 | using cd = complex; 12 | #else 13 | using cd = int; 14 | #endif 15 | 16 | class Polynomial { 17 | static const int root = 565042129; 18 | static const int root_1 = 950391366; 19 | static const int root_pw = 1 << 20; 20 | static const int mod = 998244353; 21 | 22 | static int __mod_pow(int a, int n) { 23 | int res = 1; 24 | 25 | for (a %= mod; n > 0; n >>= 1) { 26 | if (n & 1) 27 | res = (int)((1LL * res * a) % mod); 28 | a = (int)((a * 1ll * a) % mod); 29 | } 30 | return res; 31 | } 32 | 33 | public: 34 | int order; 35 | vector coeff; 36 | 37 | explicit Polynomial() : order(0), coeff(vector(0)) { 38 | } 39 | 40 | explicit Polynomial(vector coefficients) 41 | : order((int)coefficients.size()), coeff(coefficients) { 42 | } 43 | 44 | Polynomial(const Polynomial ©) 45 | : order(copy.order), coeff(vector(copy.coeff)) { 46 | } 47 | void resize(int nOrder) { 48 | int size = 1 << (long long)ceil(log2(nOrder)); 49 | coeff.resize(size, 0); 50 | } 51 | 52 | #ifdef IS_FFT 53 | void fft(bool invert = false) { 54 | int n = (int)coeff.size(); 55 | 56 | for (int i = 1, j = 0; i < n; i++) { 57 | int bit = n >> 1; 58 | for (; j & bit; bit >>= 1) 59 | j ^= bit; 60 | j ^= bit; 61 | 62 | if (i < j) 63 | swap(coeff[i], coeff[j]); 64 | } 65 | 66 | for (int len = 2; len <= n; len <<= 1) { 67 | double ang = 2 * PI / len * (invert ? -1 : 1); 68 | cd wlen(cos(ang), sin(ang)); 69 | for (int i = 0; i < n; i += len) { 70 | cd w(1); 71 | for (int j = 0; j < len / 2; j++) { 72 | cd u = coeff[i + j], v = coeff[i + j + len / 2] * w; 73 | coeff[i + j] = u + v; 74 | coeff[i + j + len / 2] = u - v; 75 | w *= wlen; 76 | } 77 | } 78 | } 79 | 80 | if (invert) { 81 | for (cd &x : coeff) 82 | x /= n; 83 | } 84 | } 85 | #else 86 | void fft(bool invert = false) { 87 | int n = (int)coeff.size(); 88 | 89 | for (int i = 1, j = 0; i < n; i++) { 90 | int bit = n >> 1; 91 | for (; j & bit; bit >>= 1) 92 | j ^= bit; 93 | j ^= bit; 94 | 95 | if (i < j) 96 | swap(coeff[i], coeff[j]); 97 | } 98 | 99 | for (int len = 2; len <= n; len <<= 1) { 100 | int wlen = invert ? root_1 : root; 101 | for (int i = len; i < root_pw; i <<= 1) 102 | wlen = (int)(1LL * wlen * wlen % mod); 103 | 104 | for (int i = 0; i < n; i += len) { 105 | int w = 1; 106 | for (int j = 0; j < len / 2; j++) { 107 | int u = coeff[i + j], 108 | v = (int)(1LL * coeff[i + j + len / 2] * w % mod); 109 | coeff[i + j] = u + v < mod ? u + v : u + v - mod; 110 | coeff[i + j + len / 2] = u - v >= 0 ? u - v : u - v + mod; 111 | w = (int)(1LL * w * wlen % mod); 112 | } 113 | } 114 | } 115 | 116 | if (invert) { 117 | int n_1 = __mod_pow(n, mod - 2); 118 | for (auto &x : coeff) 119 | x = (int)(1LL * x * n_1 % mod); 120 | } 121 | } 122 | #endif 123 | 124 | friend Polynomial operator*(const Polynomial &a, const Polynomial &b) { 125 | Polynomial x(a), y(b); 126 | 127 | int order = a.order + b.order; 128 | order = 1 << (ll)ceil(log2(order)); 129 | x.resize(order); 130 | y.resize(order); 131 | 132 | x.fft(); 133 | y.fft(); 134 | 135 | for (int i = 0; i < order; i++) { 136 | #ifdef IS_FFT 137 | x.coeff[i] = (x.coeff[i] * y.coeff[i]); 138 | #else 139 | x.coeff[i] = (int)((1ll * x.coeff[i] * y.coeff[i]) % mod); 140 | #endif 141 | } 142 | x.fft(true); 143 | return x; 144 | } 145 | 146 | friend Polynomial operator^(const Polynomial &a, int power) { 147 | Polynomial x(a); 148 | int order = a.order * power; 149 | x.resize(order); 150 | x.fft(); 151 | int size = (int)x.coeff.size(); 152 | vector poly(size); 153 | Polynomial res(poly); 154 | 155 | #ifdef IS_FFT 156 | for (int i = 0; i < size; i++) 157 | poly[i] = pow(x.coeff[i], power); 158 | #else 159 | for (int i = 0; i < size; i++) 160 | poly[i] = __mod_pow(x.coeff[i], power); 161 | #endif 162 | 163 | res.fft(true); 164 | res.order = order; 165 | return res; 166 | } 167 | }; 168 | 169 | /** 170 | * Code for finding closest match by Hamming distance of r in s |r| <= |s| 171 | * we reverse polynomial r and multiply with s 172 | * for (ll i = (int)r.size() - 1 - 1; i < s.size(); i++) { 173 | * res[i] += z.coeff[i]; // z is the multiplication result 174 | * } 175 | * answers contained in res[sz(r) - 1] to res[sz(s) - 1] 176 | */ 177 | 178 | #endif // CODE_FASTFOURIER_H -------------------------------------------------------------------------------- /code/FlowAlgorithms.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_FLOW_ALGORITHMS_H 2 | #define CODE_FLOW_ALGORITHMS_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | struct Dinic { 7 | struct Edge { 8 | int u, v; 9 | ll cap, flow; 10 | Edge() : u(0), v(0), cap(0), flow(0) { 11 | } 12 | Edge(int uu, int vv, ll ccap) : u(uu), v(vv), cap(ccap), flow(0) { 13 | } 14 | }; 15 | 16 | int size; 17 | vector edges; 18 | vector> adjacency; 19 | vector d, pt; 20 | Dinic(int NN) : size(NN), edges(0), adjacency(size), d(size), pt(size) { 21 | } 22 | void add_edge(int u, int v, ll cap_f, ll cap_r = 0) { 23 | if (u != v) { 24 | edges.emplace_back(Edge(u, v, cap_f)); 25 | adjacency[u].emplace_back(edges.size() - 1); 26 | edges.emplace_back(Edge(v, u, cap_r)); 27 | adjacency[v].emplace_back(edges.size() - 1); 28 | } 29 | } 30 | bool __bfs(int source, int sink) { 31 | queue q({source}); 32 | fill(d.begin(), d.end(), size + 1); 33 | d[source] = 0; 34 | while (!q.empty()) { 35 | int u = q.front(); 36 | q.pop(); 37 | if (u == sink) 38 | break; 39 | for (int k : adjacency[u]) { 40 | Edge &e = edges[k]; 41 | if (e.flow < e.cap && d[e.v] > d[e.u] + 1) { 42 | d[e.v] = d[e.u] + 1; 43 | q.emplace(e.v); 44 | } 45 | } 46 | } 47 | return d[sink] != size + 1; 48 | } 49 | 50 | ll __dfs(int u, int sink, ll flow = -1) { 51 | if (u == sink || flow == 0) 52 | return flow; 53 | for (int &i = pt[u]; i < (int)adjacency[u].size(); ++i) { 54 | Edge &e = edges[adjacency[u][i]]; 55 | Edge &oe = edges[adjacency[u][i] ^ 1]; 56 | if (d[e.v] == d[e.u] + 1) { 57 | ll amt = e.cap - e.flow; 58 | if (flow != -1 && amt > flow) 59 | amt = flow; 60 | if (ll pushed = __dfs(e.v, sink, amt)) { 61 | e.flow += pushed; 62 | oe.flow -= pushed; 63 | return pushed; 64 | } 65 | } 66 | } 67 | return 0; 68 | } 69 | ll max_flow(int source, int sink) { 70 | ll total = 0; 71 | while (__bfs(source, sink)) { 72 | fill(pt.begin(), pt.end(), 0); 73 | while (ll flow = __dfs(source, sink)) 74 | total += flow; 75 | } 76 | return total; 77 | } 78 | }; 79 | 80 | struct PushRelabel { 81 | struct Edge { 82 | ll from, to, cap, flow, index; 83 | Edge(ll dfrom, ll dto, ll dcap, ll dflow, ll dindex) 84 | : from(dfrom), to(dto), cap(dcap), flow(dflow), index(dindex) { 85 | } 86 | }; 87 | 88 | ll size; 89 | vector> graph; 90 | vector excess; 91 | vector dist, active, count; 92 | queue q; 93 | 94 | PushRelabel(ll n) 95 | : size(n), 96 | graph(size), 97 | excess(size), 98 | dist(size), 99 | active(size), 100 | count(2 * size) { 101 | } 102 | void add_edge(ll from, ll to, ll cap) { 103 | graph[from].push_back(Edge(from, to, cap, 0, graph[to].size())); 104 | if (from == to) 105 | graph[from].back().index++; 106 | graph[to].push_back(Edge(to, from, 0, 0, graph[from].size() - 1)); 107 | } 108 | void __enqueue(ll v) { 109 | if (!active[v] && excess[v] > 0) { 110 | active[v] = true; 111 | q.push(v); 112 | } 113 | } 114 | void __push(Edge &e) { 115 | ll amt = ll(min(excess[e.from], ll(e.cap - e.flow))); 116 | if (dist[e.from] <= dist[e.to] || amt == 0) 117 | return; 118 | e.flow += amt; 119 | graph[e.to][e.index].flow -= amt; 120 | excess[e.to] += amt; 121 | excess[e.from] -= amt; 122 | __enqueue(e.to); 123 | } 124 | void __gap(ll k) { 125 | for (ll v = 0; v < size; v++) { 126 | if (dist[v] < k) 127 | continue; 128 | count[dist[v]]--; 129 | dist[v] = max(dist[v], size + 1); 130 | count[dist[v]]++; 131 | __enqueue(v); 132 | } 133 | } 134 | void __relabel(ll v) { 135 | count[dist[v]]--; 136 | dist[v] = 2 * size; 137 | for (ll i = 0; i < (ll)graph[v].size(); i++) 138 | if (graph[v][i].cap - graph[v][i].flow > 0) 139 | dist[v] = min(dist[v], dist[graph[v][i].to] + 1); 140 | count[dist[v]]++; 141 | __enqueue(v); 142 | } 143 | void __discharge(ll v) { 144 | for (ll i = 0; excess[v] > 0 && i < (ll)graph[v].size(); i++) 145 | __push(graph[v][i]); 146 | if (excess[v] > 0) { 147 | if (count[dist[v]] == 1) 148 | __gap(dist[v]); 149 | else 150 | __relabel(v); 151 | } 152 | } 153 | ll max_flow(ll s, ll t) { 154 | count[0] = size - 1; 155 | count[size] = 1; 156 | dist[s] = size; 157 | active[s] = active[t] = true; 158 | for (ll i = 0; i < (ll)graph[s].size(); i++) { 159 | excess[s] += graph[s][i].cap; 160 | __push(graph[s][i]); 161 | } 162 | while (!q.empty()) { 163 | ll v = q.front(); 164 | q.pop(); 165 | active[v] = false; 166 | __discharge(v); 167 | } 168 | ll totflow = 0; 169 | for (ll i = 0; i < (ll)graph[s].size(); i++) 170 | totflow += graph[s][i].flow; 171 | return totflow; 172 | } 173 | }; 174 | 175 | struct HopcroftKarp { 176 | static const int INF = 1e9; 177 | int size_u, size_v, nil; 178 | vector pair_u, pair_v, dist; 179 | vector> adjacency; 180 | 181 | bool __bfs() { 182 | queue q; 183 | for (int u = 0; u < size_u; u++) 184 | if (pair_u[u] == nil) 185 | dist[u] = 0, q.push(u); 186 | else 187 | dist[u] = INF; 188 | dist[nil] = INF; 189 | while (not q.empty()) { 190 | int u = q.front(); 191 | q.pop(); 192 | if (dist[u] >= dist[nil]) 193 | continue; 194 | for (int v : adjacency[u]) 195 | if (dist[pair_v[v]] == INF) 196 | dist[pair_v[v]] = dist[u] + 1, q.push(pair_v[v]); 197 | } 198 | return dist[nil] != INF; 199 | } 200 | bool __dfs(int u) { 201 | if (u == nil) 202 | return true; 203 | for (int v : adjacency[u]) 204 | if (dist[pair_v[v]] == dist[u] + 1) 205 | if (__dfs(pair_v[v])) { 206 | pair_v[v] = u, pair_u[u] = v; 207 | return true; 208 | } 209 | dist[u] = INF; 210 | return false; 211 | } 212 | 213 | public: 214 | HopcroftKarp(int u_size, int v_size) { 215 | nil = size_u = size_v = max(u_size, v_size); 216 | adjacency.resize(size_u + 1); 217 | dist.resize(size_u + 1); 218 | pair_u.resize(size_u + 1); 219 | pair_v.resize(size_v); 220 | } 221 | void add_edge(int u, int v) { 222 | adjacency[u].push_back(v); 223 | } 224 | int max_match() { 225 | fill(pair_u.begin(), pair_u.end(), nil); 226 | fill(pair_v.begin(), pair_v.end(), nil); 227 | int res = 0; 228 | while (__bfs()) 229 | for (int u = 0; u < size_u; u++) 230 | if (pair_u[u] == nil && __dfs(u)) 231 | res++; 232 | return res; 233 | } 234 | }; 235 | 236 | #endif // CODE_FLOW_ALGORITHMS_H 237 | -------------------------------------------------------------------------------- /code/Geometry.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_GEOMETRY_H 2 | #define CODE_GEOMETRY_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | class Point { 7 | public: 8 | typedef long long coord_t; 9 | coord_t x, y; 10 | 11 | Point(coord_t coord_x = 0, coord_t coord_y = 0) { 12 | this->x = coord_x; 13 | this->y = coord_y; 14 | } 15 | Point(pair coord) { 16 | this->x = coord.first; 17 | this->y = coord.second; 18 | } 19 | static coord_t area(const Point &a, const Point &b, const Point &c) { 20 | // Area function: area < 0 = clockwise, area > 0 counterclockwise 21 | return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y); 22 | }; 23 | static coord_t area(const vector &polygon) { 24 | int n = polygon.size(); 25 | coord_t ans = 0; 26 | for (int i = 0; i < n; i++) { 27 | ans += polygon[i].x * polygon[(i + 1) % n].y - 28 | polygon[i].y * polygon[(i + 1) % n].x; 29 | } 30 | } 31 | friend bool operator<(const Point &a, const Point &b) { 32 | return (a.x != b.x) ? a.x < b.x : a.y < b.y; 33 | } 34 | friend bool operator==(const Point &a, const Point &b) { 35 | return (a.x == b.x) && (a.y == b.y); 36 | } 37 | friend istream &operator>>(istream &in, Point &p) { 38 | in >> p.x >> p.y; 39 | return in; 40 | } 41 | friend ostream &operator<<(ostream &out, Point &p) { 42 | out << p.x << " " << p.y; 43 | return out; 44 | } 45 | static coord_t sq_dist(const Point &a, const Point &b) { 46 | return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); 47 | } 48 | 49 | static vector convex_hull(vector &a) { 50 | if (a.size() <= 3) 51 | return a; 52 | int n = a.size(), k = 0; 53 | sort(a.begin(), a.end()); 54 | vector result(2 * n); 55 | for (int i = 0; i < n; ++i) { 56 | while (k >= 2 && area(result[k - 2], result[k - 1], a[i]) <= 0) 57 | k--; 58 | result[k++] = a[i]; 59 | } 60 | for (int i = n - 1, t = k + 1; i > 0; --i) { 61 | while (k >= t && area(result[k - 2], result[k - 1], a[i - 1]) <= 0) 62 | k--; 63 | result[k++] = a[i - 1]; 64 | } 65 | result.resize(k - 1); 66 | return result; 67 | } 68 | }; 69 | 70 | double closest_pair(const vpl &pt, int n) { 71 | double best = FLT_MAX; 72 | set box; 73 | box.insert(pt[0]); 74 | int left = 0; 75 | for (int i = 1; i < n; ++i) { 76 | while (left < i && pt[i].second - pt[left].second > sqrt(best)) 77 | box.erase(pt[left++]); 78 | ll cnt = 0; 79 | for (auto it = box.lower_bound( 80 | {pt[i].first - sqrt(best), pt[i].second - sqrt(best)}); 81 | it != box.end() && pt[i].first + sqrt(best) >= it->first; it++) { 82 | cnt++; 83 | best = min(best, (pow(pt[i].first - it->first, 2.0) + 84 | pow(pt[i].second - it->second, 2.0))); 85 | } 86 | box.insert(pt[i]); 87 | } 88 | return best; 89 | } 90 | 91 | #endif // CODE_GEOMETRY_H -------------------------------------------------------------------------------- /code/Graphs.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_GRAPH_H 2 | #define CODE_GRAPH_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | class Graph { 7 | public: 8 | enum NodeColor { VISITED, VISITING, UNVISITED }; 9 | struct Node { 10 | int index; 11 | vpl adjacent; 12 | NodeColor color = UNVISITED; 13 | }; 14 | vector list; 15 | int n; 16 | Graph(int n) { 17 | list.resize(n); 18 | for (int i = 0; i < n; i++) 19 | list[i].index = i; 20 | this->n = n; 21 | } 22 | void add_edge(int u, int v, long long w = 1, bool bidirectional = true) { 23 | list[u].adjacent.emplace_back(v, w); 24 | if (bidirectional) 25 | list[v].adjacent.emplace_back(u, w); 26 | } 27 | 28 | pair dijkstra(vll from) { 29 | vll dist(n, INT64_MAX), parent(n, INT32_MAX); 30 | priority_queue> q; 31 | // q: (distance, node id); edge: (to, weight) 32 | for (auto index : from) { 33 | dist[index] = 0; 34 | q.emplace(0, index); 35 | } 36 | while (!q.empty()) { 37 | pll top = q.top(); 38 | q.pop(); 39 | if (top.first > dist[top.second]) 40 | continue; 41 | for (auto edge : list[top.second].adjacent) { 42 | if (top.first + edge.second < dist[edge.first]) { 43 | dist[edge.first] = top.first + edge.second; 44 | parent[edge.first] = top.second - 1; 45 | q.emplace(top.first + edge.second, edge.first); 46 | } 47 | } 48 | } 49 | return {dist, parent}; 50 | } 51 | 52 | // Returns sorted vector of indices 53 | vector topological_sort() { 54 | vector in_degree(list.size(), 0), result; 55 | result.reserve(list.size()); 56 | for (auto node : list) 57 | for (auto route : node.adjacent) 58 | in_degree[route.first - 1]++; 59 | queue process; 60 | for (int i = 0; i < list.size(); i++) { 61 | if (in_degree[i] == 0) { 62 | process.push(i); 63 | result.push_back(i); 64 | } 65 | } 66 | while (!process.empty()) { 67 | int processing = process.front(); 68 | process.pop(); 69 | for (auto route : list[processing].adjacent) { 70 | in_degree[route.first - 1]--; 71 | if (in_degree[route.first - 1] == 0) { 72 | process.push(route.first - 1); 73 | result.push_back(route.first - 1); 74 | } 75 | } 76 | } 77 | return result; 78 | } 79 | 80 | mll components() { 81 | vbl visited(n); 82 | mll result(0); 83 | for (int i = 0; i < n; i++) { 84 | if (visited[i]) 85 | continue; 86 | vll component; 87 | stack process; 88 | process.push(list[i].index); 89 | component.push_back(i); 90 | visited[i] = true; 91 | while (!process.empty()) { 92 | ll processing = process.top(); 93 | process.pop(); 94 | for (pll neighbor : list[processing].adjacent) { 95 | if (!visited[neighbor.first]) { 96 | process.push(neighbor.first); 97 | component.push_back(neighbor.first); 98 | } 99 | } 100 | } 101 | result.push_back(component); 102 | } 103 | return result; 104 | } 105 | 106 | pair bellman_ford(vll from) { 107 | vll distances(n, INT64_MAX); 108 | vll parent(n, INT32_MAX); 109 | for (ll &i : from) 110 | distances[i] = 0; 111 | // relax all |E| edges, |V| - 1 times 112 | for (int i = 0; i < n - 1; i++) { 113 | for (int source = 0; source <= n - 1; source++) { 114 | if (distances[source] == INT64_MAX) 115 | continue; 116 | for (const auto &edge : list[source].adjacent) { 117 | ll sink = edge.first; 118 | if (distances[source] + edge.second < distances[sink]) { 119 | distances[sink] = distances[source] + edge.second; 120 | parent[sink] = source; 121 | } 122 | } 123 | } 124 | } 125 | // Checking for negative cycles and putting -1 if it exists. 126 | for (ll source = 0; source <= n - 1; source++) { 127 | for (const auto &edge : list[source].adjacent) { 128 | ll sink = edge.first; 129 | if (distances[source] < INT64_MAX && 130 | distances[source] + edge.second < distances[sink]) { 131 | for (ll i : from) 132 | distances[i] = INT64_MIN; 133 | return {distances, parent}; 134 | } 135 | } 136 | } 137 | return {distances, parent}; 138 | } 139 | 140 | mll floyd_warshall() { 141 | mll distances(n, vll(n, INT64_MAX)); 142 | for (int i = 0; i < n; i++) 143 | distances[i][i] = 0; 144 | for (int i = 0; i < n; i++) 145 | for (auto route : list[i].adjacent) 146 | distances[i][route.first] = route.second; 147 | for (int k = 0; k < n; k++) { 148 | for (int i = 0; i < n; i++) { 149 | for (int j = 0; j < n; j++) { 150 | if (distances[i][k] == INT64_MAX || 151 | distances[k][j] == INT64_MAX) 152 | continue; 153 | distances[i][j] = 154 | min(distances[i][j], distances[i][k] + distances[k][j]); 155 | } 156 | } 157 | } 158 | return distances; 159 | } 160 | 161 | pair prims_mst() { 162 | priority_queue> routes; 163 | vll costs(n); 164 | vbl visited(n, false); 165 | for (int i = 0; i < n; i++) { 166 | if (!visited[i]) 167 | routes.emplace(INT32_MAX, i); 168 | while (!routes.empty()) { 169 | pll best = routes.top(); 170 | routes.pop(); 171 | if (!visited[best.second]) 172 | costs[best.second] = best.first; 173 | visited[best.second] = false; 174 | for (const auto &path : list[best.second].adjacent) 175 | if (!visited[path.second]) 176 | routes.push(path); 177 | } 178 | } 179 | ll sum = accumulate(costs.begin(), costs.end(), 0); 180 | return {sum, costs}; 181 | } 182 | }; 183 | 184 | #endif // CODE_GRAPH_H 185 | -------------------------------------------------------------------------------- /code/HuffmanTree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_HUFFMAN_TREE_C 2 | #define CODE_HUFFMAN_TREE_C 3 | 4 | #include "../ref/template.hpp" 5 | 6 | struct HuffmanTree { 7 | vll prob; 8 | vector> parent; 9 | vector depth; 10 | ll size, total_prob; 11 | 12 | HuffmanTree(const vll &p) { 13 | // Initialize everything 14 | prob = vll(p); 15 | total_prob = accumulate(prob.begin(), prob.end(), 0); 16 | size = p.size(); 17 | parent = vector>(size * 2, {-1, false}); 18 | depth = vector(size); 19 | // Get the parents of each node by greedy combination 20 | priority_queue, vector>, greater<>> q; 21 | for (int i = 0; i < size; i++) 22 | q.emplace(prob[i], i); 23 | int next_free_node = size; 24 | for (int i = 0; q.size() >= 2; i++) { 25 | pair top1 = q.top(); 26 | q.pop(); 27 | pair top2 = q.top(); 28 | q.pop(); 29 | parent[top1.second] = {next_free_node, false}; 30 | parent[top2.second] = {next_free_node, true}; 31 | q.emplace(top1.first + top2.first, next_free_node); 32 | next_free_node++; 33 | } 34 | parent.resize(next_free_node); 35 | // Get all the children 36 | vector> children(2 * size, {-1, -1}); 37 | for (int i = 0; i < 2 * size; i++) { 38 | if (parent[i].first != -1) { 39 | if (children[parent[i].first].first == -1) 40 | children[parent[i].first].first = i; 41 | else if (children[parent[i].first].second == -1) 42 | children[parent[i].first].second = i; 43 | } 44 | } 45 | // Compute the depths using a dfs 46 | stack dfs; 47 | dfs.push(q.top().second); 48 | depth[q.top().second] = 0; 49 | while (!dfs.empty()) { 50 | ll top = dfs.top(); 51 | dfs.pop(); 52 | if (children[top].first != -1) { 53 | depth[children[top].first] = depth[top] + 1; 54 | dfs.push(children[top].first); 55 | } 56 | if (children[top].second != -1) { 57 | depth[children[top].second] = depth[top] + 1; 58 | dfs.push(children[top].second); 59 | } 60 | } 61 | } 62 | 63 | string get_string(int letter) { 64 | string st; 65 | for (int cur = letter; letter != -1; letter = parent[letter].first) 66 | st += (parent[letter].first ? "0" : "1"); 67 | return st; 68 | } 69 | 70 | static ll encoding_length(const vll &p) { 71 | priority_queue, greater<>> q; 72 | for (auto el : p) 73 | q.push(el); 74 | ll ans = 0; 75 | while (q.size() >= 2) { 76 | ll top1 = q.top(); 77 | q.pop(); 78 | ll top2 = q.top(); 79 | q.pop(); 80 | ans += top1 + top2; 81 | q.push(top1 + top2); 82 | } 83 | return ans; 84 | } 85 | }; 86 | 87 | #endif // CODE_HUFFMAN_TREE_C -------------------------------------------------------------------------------- /code/MergeSortTree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_MERGESORT_H 2 | #define CODE_MERGESORT_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | template 7 | struct MergeSortTree { 8 | int size; 9 | vector data; 10 | vector> tree_idx; 11 | vector> tree_val; 12 | long long inversions; 13 | 14 | template 15 | vector merge(const vector &arr1, 16 | const vector &arr2) { 17 | int n = arr1.size(), m = arr2.size(); 18 | vector result; 19 | result.reserve(n + m); 20 | for (int x = 0, y = 0; x < n || y < m;) { 21 | if (x < n && (y >= m || arr1[x] <= arr2[y])) 22 | result.push_back(arr1[x++]); 23 | else 24 | result.push_back(arr2[y++]), inversions += n - x; 25 | } 26 | return move(result); 27 | } 28 | int order_fn(const Type &value, const vector &arr) { 29 | return lower_bound(arr.begin(), arr.end(), value) - arr.begin(); 30 | } 31 | explicit MergeSortTree(const vector &list) { 32 | for (size = 1; size < list.size(); size *= 2) 33 | ; 34 | // Make a tree based on the values 35 | tree_val.resize(2 * size); 36 | data = vector(list); 37 | for (int i = 0; i < list.size(); i++) 38 | tree_val[i + size].push_back(i); 39 | for (int i = size - 1; i > 0; --i) 40 | tree_val[i] = merge(tree_val[i << 1], tree_val[i << 1 | 1]); 41 | // Make a tree based on the indices 42 | tree_idx.resize(2 * size); 43 | vector> convert(list.size()); 44 | for (int i = 0; i < list.size(); i++) 45 | convert[i].first = list[i], convert[i].second = i; 46 | sort(convert.begin(), convert.end()); 47 | for (int i = 0; i < list.size(); i++) 48 | tree_idx[i + size].push_back(convert[i].second); 49 | for (int i = size - 1; i > 0; --i) 50 | tree_idx[i] = merge(tree_idx[i << 1], tree_idx[i << 1 | 1]); 51 | } 52 | int order_of_key(int l, int r, Type value) { 53 | int result = 0; 54 | for (l = l + size, r = r + size; l < r; l >>= 1, r >>= 1) { 55 | if (l & 1) 56 | result += order_fn(value, tree_val[l++]); 57 | if (r & 1) 58 | result += order_fn(value, tree_val[--r]); 59 | } 60 | return result; 61 | } 62 | int key_of_order(int l, int r, int order, int node = 0, int x = 0, 63 | int y = -1) { 64 | if (y == -1) 65 | y = size; 66 | if (x + 1 == y) 67 | return tree_idx[node][0]; 68 | int m = (upper_bound(tree_idx[2 * node].begin(), 69 | tree_idx[2 * node].end(), r - 1) - 70 | tree_idx[2 * node].begin()) - 71 | (lower_bound(tree_idx[2 * node].begin(), 72 | tree_idx[2 * node].end(), l) - 73 | tree_idx[2 * node].begin()); 74 | if (m >= order) 75 | return key_of_order(l, r, order, node << 1, x, (x + y) / 2); 76 | else 77 | return key_of_order(l, r, order - m, node << 1 | 1, (x + y) / 2, y); 78 | } 79 | }; 80 | 81 | long long __inversions = 0; 82 | void __merge(int *A, int start, int mid, int end) { 83 | int result[end - start]; 84 | for (int x = start, y = mid; x < mid || y < end;) { 85 | if (x < mid && (y >= end || A[x] <= A[y])) { 86 | result[x + y - start - mid] = A[x]; 87 | x++; 88 | } else { 89 | result[x + y - start - mid] = A[y]; 90 | y++; 91 | __inversions += mid - x; 92 | } 93 | } 94 | for (int i = start; i < end; i++) 95 | A[i] = result[i - start]; 96 | } 97 | void sort(int A[], int start, int end) { 98 | if (start >= end - 1) 99 | return; 100 | sort(A, start, (start + end) / 2); 101 | sort(A, (start + end) / 2, end); 102 | __merge(A, start, (start + end) / 2, end); 103 | } 104 | 105 | #endif -------------------------------------------------------------------------------- /code/MinMaxHeap.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_MINMAXHEAP_H 2 | #define CODE_MINMAXHEAP_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | /* 12 | * A container for MinMaxHeap 13 | * 14 | * Based on the original 1986 paper 15 | * https://cglab.ca/~morin/teaching/5408/refs/minmax.pdf 16 | */ 17 | class MinMaxHeap { 18 | private: 19 | vector heap; 20 | bool _is_min_level(long long index); 21 | void _sift_down(long long index); 22 | void _sift_down_min(long long index); 23 | void _sift_down_max(long long index); 24 | void _sift_down_generic(long long index, 25 | function comp); 26 | void _sift_up(long long index); 27 | void _sift_up_min(long long index); 28 | void _sift_up_max(long long index); 29 | void _sift_up_grandparent_generic( 30 | long long index, function comp); 31 | void swap(long long a, long long b); 32 | 33 | public: 34 | MinMaxHeap(); 35 | MinMaxHeap(vector base); 36 | void insert(long long n); 37 | long long get_max(); 38 | long long get_min(); 39 | long long size(); 40 | bool empty(); 41 | long long pop_min(); 42 | long long pop_max(); 43 | vector heapify(vector base); 44 | static bool _min_heap_comparator(long long a, long long b); 45 | static bool _max_heap_comparator(long long a, long long b); 46 | void print(); 47 | }; 48 | 49 | MinMaxHeap::MinMaxHeap() { 50 | heap = vector(0); 51 | heap.push_back(0); // push in a dummy element 52 | } 53 | 54 | // create new object based on the given array 55 | // using heapify method 56 | MinMaxHeap::MinMaxHeap(vector base) { 57 | heap = MinMaxHeap::heapify(base); 58 | } 59 | 60 | bool MinMaxHeap::_is_min_level(long long index) { 61 | return ((long long)floor(log2(index)) + 1) & 1; 62 | } 63 | 64 | bool MinMaxHeap::_min_heap_comparator(long long parent, long long child) { 65 | return parent < child; 66 | } 67 | 68 | bool MinMaxHeap::_max_heap_comparator(long long parent, long long child) { 69 | return parent > child; 70 | } 71 | 72 | void MinMaxHeap::_sift_down(long long index) { 73 | if (_is_min_level(index)) { 74 | _sift_down_min(index); 75 | } else { 76 | _sift_down_max(index); 77 | } 78 | } 79 | 80 | void MinMaxHeap::swap(long long a, long long b) { 81 | long long t = heap[a]; 82 | heap[a] = heap[b]; 83 | heap[b] = t; 84 | } 85 | 86 | void MinMaxHeap::_sift_down_min(long long index) { 87 | _sift_down_generic(index, _min_heap_comparator); 88 | } 89 | 90 | void MinMaxHeap::_sift_down_max(long long index) { 91 | _sift_down_generic(index, _max_heap_comparator); 92 | } 93 | 94 | void MinMaxHeap::_sift_down_generic(long long index, 95 | function comp) { 96 | long long m = index; 97 | // find smallest node among children and grandchildren 98 | vector indicesToCheck = {2 * index, 2 * index + 1, 99 | 4 * index, 4 * index + 1, 100 | 4 * index + 2, 4 * index + 3}; 101 | for (auto idx : indicesToCheck) { 102 | if (idx <= (long long)heap.size() - 1 && !comp(heap[m], heap[idx])) 103 | m = idx; 104 | } 105 | // curr node itself is smallest 106 | if (m == index) 107 | return; 108 | // bring smallest node of subtree to current pos 109 | swap(m, index); 110 | // when smallest node is a grandchild 111 | if (m > 2 * index + 1) { 112 | // check additional case for even level 113 | if (m > 1 && !comp(heap[m], heap[m / 2])) 114 | swap(m, m / 2); 115 | // recursively go ahead 116 | _sift_down_generic(m, comp); 117 | } 118 | } 119 | 120 | void MinMaxHeap::print() { 121 | for (auto x : heap) { 122 | cout << x << " "; 123 | } 124 | cout << "\n"; 125 | } 126 | 127 | void MinMaxHeap::_sift_up(long long index) { 128 | // cannot siftup root 129 | if (index == 1) 130 | return; 131 | if (_is_min_level(index)) { 132 | if (!_max_heap_comparator(heap[index / 2], heap[index])) { 133 | swap(index, index / 2); 134 | _sift_up_max(index / 2); 135 | } else { 136 | _sift_up_min(index); 137 | } 138 | } else { 139 | if (!_min_heap_comparator(heap[index / 2], heap[index])) { 140 | swap(index, index / 2); 141 | _sift_up_min(index / 2); 142 | } else { 143 | _sift_up_max(index); 144 | } 145 | } 146 | } 147 | 148 | void MinMaxHeap::_sift_up_min(long long index) { 149 | _sift_up_grandparent_generic(index, _min_heap_comparator); 150 | } 151 | 152 | void MinMaxHeap::_sift_up_max(long long index) { 153 | _sift_up_grandparent_generic(index, _max_heap_comparator); 154 | } 155 | 156 | void MinMaxHeap::_sift_up_grandparent_generic( 157 | long long index, function comp) { 158 | // does not have grandparent 159 | long long gp = index / 4; 160 | if (gp == 0) 161 | return; 162 | if (!comp(heap[gp], heap[index])) { 163 | swap(gp, index); 164 | _sift_up_min(gp); 165 | } 166 | } 167 | 168 | // O(log n) 169 | void MinMaxHeap::insert(long long n) { 170 | heap.push_back(n); 171 | _sift_up(heap.size() - 1); 172 | } 173 | 174 | bool MinMaxHeap::empty() { 175 | return heap.size() == 1; 176 | } 177 | 178 | // O(1) 179 | long long MinMaxHeap::get_max() { 180 | if (empty()) { 181 | return -1; 182 | } 183 | return heap.size() > 3 ? max(heap[3], heap[2]) 184 | : heap.size() > 2 ? heap[2] : heap[1]; 185 | } 186 | 187 | // O(1) 188 | long long MinMaxHeap::get_min() { 189 | if (empty()) { 190 | return -1; 191 | } 192 | return heap[1]; 193 | } 194 | 195 | long long MinMaxHeap::pop_min() { 196 | if (empty()) { 197 | return -1; 198 | } 199 | long long mi = get_min(); 200 | swap(1, heap.size() - 1); 201 | heap.pop_back(); 202 | print(); 203 | _sift_down(1); 204 | print(); 205 | return mi; 206 | } 207 | 208 | long long MinMaxHeap::pop_max() { 209 | if (empty()) { 210 | return -1; 211 | } 212 | 213 | long long ma = get_max(); 214 | if (heap.size() == 2 || heap.size() == 3) { 215 | heap.pop_back(); 216 | return ma; 217 | } else { 218 | long long maIndex = 2; 219 | if (heap[3] > heap[2]) 220 | maIndex = 3; 221 | swap(maIndex, heap.size() - 1); 222 | heap.pop_back(); 223 | _sift_down(maIndex); 224 | return ma; 225 | } 226 | } 227 | 228 | long long MinMaxHeap::size() { 229 | return heap.size() - 1; 230 | } 231 | 232 | /* 233 | * Parameters 234 | * vector base: a one-based array that needs to be heapified 235 | */ 236 | vector MinMaxHeap::heapify(vector base) { 237 | long long n = base.size(); 238 | vector heap(base.begin(), base.end()); // work on a copy 239 | 240 | for (long long i = n; i >= 1; i--) { 241 | _sift_down(i); 242 | } 243 | 244 | return heap; 245 | } 246 | 247 | #endif -------------------------------------------------------------------------------- /code/NumberTheory.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_NUMBERTHEORY_H 2 | #define CODE_NUMBERTHEORY_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | /** 7 | * Modular Arithmetic functions 8 | * ============================ 9 | */ 10 | 11 | long long modPower(long long a, long long b, long long MOD) { 12 | long long cumulative = a, result = 1; 13 | for (; b > 0; b /= 2) { 14 | if (b % 2 == 1) 15 | result = (result * a) % MOD; 16 | cumulative = (cumulative * cumulative) % MOD; 17 | } 18 | return result; 19 | } 20 | 21 | long long modMultiply(long long a, long long b, long long MOD) { 22 | long long cumulative = a, result = 0; 23 | for (; b > 0; b /= 2) { 24 | if (b % 2 == 1) 25 | result = (result + a) % MOD; 26 | cumulative = (cumulative + cumulative) % MOD; 27 | } 28 | return result; 29 | } 30 | 31 | long long modInverse(long long a, long long MOD) { 32 | return modPower(a, MOD - 2, MOD); 33 | } 34 | 35 | /** 36 | * GCD and Prime Factorization 37 | * =========================== 38 | */ 39 | 40 | long long gcd(long long a, long long b) { 41 | if (b == 0) 42 | return a; 43 | return gcd(b, a % b); 44 | } 45 | 46 | vector prime_factorize(long long x) { 47 | vector result; 48 | if (x < 0) { 49 | x = -x; 50 | result.push_back(-1); 51 | } 52 | for (int i = 2; i <= sqrt(x); i++) { 53 | while (x % i == 0) { 54 | result.push_back(i); 55 | x /= i; 56 | } 57 | } 58 | if (x > 1) 59 | result.push_back(x); 60 | return result; 61 | } 62 | 63 | /** 64 | * Multiplicative Function Sieve 65 | * ============================= 66 | */ 67 | 68 | typedef long long ll; 69 | 70 | class Multiplicative { 71 | // This is the definition for PHI 72 | #define fn_prime_values(prime) (prime - 1) 73 | #define fn_non_coprime(num, prime) (fn[num] * prime) 74 | public: 75 | ll size; 76 | vector fn; 77 | vector primes; 78 | vector lowest_prime_factor; 79 | 80 | Multiplicative(ll size) { 81 | size = size; 82 | lowest_prime_factor = vector(size, 0); 83 | fn = vector(size, 0); 84 | // https://stackoverflow.com/questions/34260399 85 | // linear sieve 86 | for (ll i = 2; i < size; i++) 87 | lowest_prime_factor[i] = i; 88 | // put any specific initialization code here like 89 | // multiplicativeFn[1] = 1; 90 | for (ll i = 2; i < size; i++) { 91 | if (lowest_prime_factor[i] == i) { 92 | fn[i] = fn_prime_values(i); 93 | primes.push_back(i); 94 | } 95 | 96 | for (auto p : primes) { 97 | ll ith_multiple = i * p; 98 | if (ith_multiple >= size) 99 | break; 100 | 101 | lowest_prime_factor[ith_multiple] = 102 | min(lowest_prime_factor[i], p); 103 | 104 | if (i % p) { 105 | fn[ith_multiple] = fn[i] * fn[p]; 106 | } else { 107 | fn[ith_multiple] = fn_non_coprime(i, p); 108 | break; 109 | } 110 | } 111 | } 112 | } 113 | }; 114 | 115 | #endif // CODE_NUMBERTHEORY_H -------------------------------------------------------------------------------- /code/PersistentSegTree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_SEGTREE_H 2 | #define CODE_SEGTREE_H 3 | 4 | #include "../ref/template.hpp" 5 | template 6 | class PersistantSegTree{ 7 | private: 8 | int Nodes=0,N,n; 9 | vectorseg,lp,rp; 10 | // persistant seg tree for range sum and point update 11 | int build(int ss,int se,vector&a) 12 | { 13 | int pos=Nodes++; 14 | if(ss==se) 15 | { 16 | seg[pos]=a[ss]; 17 | lp[pos]=-1; 18 | rp[pos]=-1; 19 | return pos; 20 | } 21 | int mid=(ss+se)/2; 22 | lp[pos]=build(ss,mid,a); 23 | rp[pos]=build(mid+1,se,a); 24 | seg[pos]=seg[lp[pos]]+seg[rp[pos]]; 25 | return pos; 26 | } 27 | int update(int root,int ss,int se,int ind,int val){ 28 | if(ind < ss || ind > se) 29 | return root; 30 | int pos=Nodes++; 31 | if(ss == se) 32 | { 33 | seg[pos]=val; 34 | return pos; 35 | } 36 | int mid=(ss+se)/2; 37 | if(ind <=mid) 38 | { 39 | lp[pos]=update(lp[root],ss,mid,ind,val); 40 | rp[pos]=rp[root]; 41 | seg[pos]=seg[lp[pos]]+seg[rp[pos]]; 42 | return pos; 43 | } 44 | else 45 | { 46 | rp[pos]=update(rp[root],mid+1,se,ind,val); 47 | lp[pos]=lp[root]; 48 | seg[pos]=seg[lp[pos]]+seg[rp[pos]]; 49 | return pos; 50 | } 51 | } 52 | type query(int pos,int ss,int se,int l,int r) 53 | { 54 | if(l <=ss && r>=se) 55 | return seg[pos]; 56 | if(l > se || r < ss) 57 | return 0; 58 | int mid=(ss+se)/2; 59 | return query(lp[pos],ss,mid,l,r)+query(rp[pos],mid+1,se,l,r); 60 | } 61 | public: 62 | PersistantSegTree(vector&a) 63 | { 64 | n=a.size(); 65 | N=4*n+1; 66 | seg.resize(N,0); 67 | lp.resize(N,-1) 68 | rp.resize(N,-1); 69 | build(0,n-1,a); 70 | } 71 | int Update(int root,int ind,int val) 72 | { 73 | return update(root,0,n-1,ind,val); 74 | } 75 | type Query(int root,int l,int r) 76 | { 77 | return query(root,0,n-1,l,r); 78 | } 79 | }; 80 | 81 | 82 | -------------------------------------------------------------------------------- /code/SearchString.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_SMARTSTRING_H 2 | #define CODE_SMARTSTRING_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | class KMPstring { 7 | string pattern; 8 | vll lps; 9 | 10 | public: 11 | explicit KMPstring(const string &pattern) { 12 | this->pattern = pattern; 13 | ll m = pattern.size(); 14 | lps = vll(m + 1, 0); 15 | ll i = 0, j = -1; 16 | lps[0] = -1; 17 | while (i < m) { 18 | while (j >= 0 && pattern[i] != pattern[j]) 19 | j = lps[j]; 20 | i++, j++; 21 | lps[i] = j; 22 | } 23 | } 24 | vll match(const string &text) { 25 | ll n = text.size(), m = pattern.size(); 26 | vll matches, m_length(n); 27 | ll i = 0, j = 0; 28 | while (i < n) { 29 | while (j >= 0 && text[i] != pattern[j]) 30 | j = lps[j]; 31 | i++, j++; 32 | m_length[i - 1] = j; 33 | if (j == m) { 34 | matches.push_back(i - m); 35 | j = lps[j]; 36 | } 37 | } 38 | return move(matches); // or m_length 39 | } 40 | }; 41 | 42 | class SuffixArray { 43 | public: 44 | string s; 45 | int n, __log_n; 46 | vector sa; // Suffix Array 47 | vector> ra; // Rank Array 48 | vector> _lcp; // Longest Common Prefix 49 | vector __msb, __dollar; 50 | 51 | SuffixArray(string st) { 52 | n = st.size(); 53 | __log_n = log2(n) + 2; 54 | ra = vector>(__log_n, vector(n)); 55 | sa = vector(n); 56 | 57 | __msb = vector(n); 58 | int mx = -1; 59 | for (int i = 0; i < n; i++) { 60 | if (i >= (1 << (mx + 1))) 61 | mx++; 62 | __msb[i] = mx; 63 | } 64 | this->s = st; 65 | build_SA(); 66 | } 67 | 68 | void __counting_sort(int l, int k) { 69 | int maxi = max(300, n); 70 | vector count(maxi, 0), temp_sa(n, 0); 71 | for (int i = 0; i < n; i++) { 72 | int idx = (i + k < n ? ra[l][i + k] : 0); 73 | count[idx]++; 74 | } 75 | for (int i = 0, sum = 0; i < maxi; i++) { 76 | int t = count[i]; 77 | count[i] = sum; 78 | sum += t; 79 | } 80 | for (int i = 0; i < n; i++) { 81 | int idx = sa[i] + k < n ? ra[l][sa[i] + k] : 0; 82 | temp_sa[count[idx]++] = sa[i]; 83 | } 84 | sa = temp_sa; 85 | } 86 | 87 | void build_SA() { 88 | for (int i = 0; i < n; i++) 89 | ra[0][i] = s[i]; 90 | for (int i = 0; i < n; i++) 91 | sa[i] = i; 92 | for (int i = 0; i < __log_n - 1; i++) { 93 | int k = (1 << i); 94 | if (k >= n) 95 | break; 96 | __counting_sort(i, k); 97 | __counting_sort(i, 0); 98 | int rank = 0; 99 | ra[i + 1][sa[0]] = rank; 100 | for (int j = 1; j < n; j++) 101 | if (ra[i][sa[j]] == ra[i][sa[j - 1]] && 102 | ra[i][sa[j] + k] == ra[i][sa[j - 1] + k]) 103 | ra[i + 1][sa[j]] = rank; 104 | else 105 | ra[i + 1][sa[j]] = ++rank; 106 | } 107 | } 108 | void build_LCP() { 109 | _lcp = vector>(__log_n, vector(n)); 110 | for (int i = 0; i < n - 1; i++) { // Build the LCP array in O(NlogN) 111 | int x = sa[i], y = sa[i + 1], k, ret = 0; 112 | for (k = __log_n - 1; k >= 0 && x < n && y < n; k--) { 113 | if ((1 << k) >= n) 114 | continue; 115 | if (ra[k][x] == ra[k][y]) 116 | x += 1 << k, y += 1 << k, ret += 1 << k; 117 | } 118 | if (ret >= __dollar[sa[i]] - sa[i]) 119 | ret = __dollar[sa[i]] - sa[i]; 120 | _lcp[0][i] = ret; // LCP[i] shouldn’t exceed __dollar[sa[i]] 121 | } // __dollar[i] : index of __dollar to the right of i. 122 | _lcp[0][n - 1] = 10 * n; 123 | for (int i = 1; i < __log_n; i++) { // O(1) RMQ structure in O(NlogN) 124 | int add = (1 << (i - 1)); 125 | if (add >= n) 126 | break; // small optimization 127 | for (int j = 0; j < n; j++) 128 | if (j + add < n) 129 | _lcp[i][j] = min(_lcp[i - 1][j], _lcp[i - 1][j + add]); 130 | else 131 | _lcp[i][j] = _lcp[i - 1][j]; 132 | } 133 | } 134 | 135 | int lcp(int x, int y) { 136 | // O(1) LCP. x & y are indexes of the suffix in sa! 137 | if (x == y) 138 | return __dollar[sa[x]] - sa[x]; 139 | if (x > y) 140 | swap(x, y); 141 | y--; 142 | int idx = __msb[y - x + 1], sub = (1 << idx); 143 | return min(_lcp[idx][x], _lcp[idx][y - sub + 1]); 144 | } 145 | 146 | bool equal(int i, int j, int p, int q) { 147 | if (j - i != q - p) 148 | return false; 149 | int idx = __msb[j - i + 1], sub = (1 << idx); 150 | return ra[idx][i] == ra[idx][p] && 151 | ra[idx][j - sub + 1] == ra[idx][q - sub + 1]; 152 | } // Note : Do not forget to add a terminating ’$’ 153 | }; 154 | 155 | #endif // CODE_SMARTSTRING_H 156 | -------------------------------------------------------------------------------- /code/Tree.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CODE_TREE_H 2 | #define CODE_TREE_H 3 | 4 | #include "../ref/template.hpp" 5 | 6 | class Tree { 7 | public: 8 | struct Node { 9 | vector adjacent; 10 | Node *parent = nullptr; 11 | long long start_time = 0, end_time = 0, subtree_size = 1; 12 | unsigned long depth = 0, height = 0; 13 | unsigned long index = INT32_MAX; 14 | }; 15 | 16 | vector list; 17 | Node *root = nullptr; 18 | vector> __anc; 19 | 20 | Tree(int n = 1e5) { 21 | list.resize(n); 22 | this->root = &list[0]; 23 | for (int i = 0; i < n; i++) 24 | list[i].index = i; 25 | } 26 | void add_edge(int x, int y) { 27 | list[x].adjacent.push_back(&list[y]); 28 | list[y].adjacent.push_back(&list[x]); 29 | } 30 | 31 | Node *lca(Node *a, Node *b) { 32 | if (b->depth > a->depth) 33 | swap(a, b); 34 | for (int ptr = __anc[0].size() - 1; a->depth > b->depth && ptr >= 0; 35 | ptr--) { 36 | if (__anc[a->index][ptr] != nullptr && 37 | __anc[a->index][ptr]->depth >= b->depth) 38 | a = __anc[a->index][ptr]; 39 | } 40 | if (a == b) 41 | return a; 42 | for (long step = __anc[0].size() - 1; step >= 0; step--) { 43 | if (__anc[a->index][step] != __anc[b->index][step]) 44 | a = __anc[a->index][step], b = __anc[b->index][step]; 45 | } 46 | return a->parent; 47 | } 48 | Node *ancestor(Node *a, int degree) { 49 | long long target_depth = a->depth - degree; 50 | for (int ptr = __anc[0].size() - 1; a->depth > target_depth && ptr >= 0; 51 | ptr--) { 52 | if (__anc[a->index][ptr] != nullptr && 53 | __anc[a->index][ptr]->depth >= target_depth) 54 | a = __anc[a->index][ptr]; 55 | } 56 | return a; 57 | } 58 | int __build(Node *root = nullptr, int time = 0) { 59 | if (root == nullptr) 60 | root = this->root; 61 | root->start_time = time; 62 | for (auto child : root->adjacent) { 63 | if (child == root->parent) 64 | continue; 65 | child->parent = root, child->depth = root->depth + 1; 66 | time = __build(child, time + 1); 67 | root->height = max(root->height, child->height + 1); 68 | root->subtree_size += child->subtree_size; 69 | } 70 | root->end_time = time; 71 | return time; 72 | } 73 | void __build_lca_matrix() { 74 | int n = list.size(); 75 | __anc.assign(n, vector(log2(n) + 1, nullptr)); 76 | for (int i = 0; i < list.size(); i++) 77 | __anc[i][0] = list[i].parent; 78 | for (int level = 1; level < __anc[0].size(); level++) 79 | for (int i = 0; i < list.size(); i++) { 80 | if (__anc[i][level - 1] == nullptr) 81 | continue; 82 | __anc[i][level] = __anc[__anc[i][level - 1]->index][level - 1]; 83 | } 84 | } 85 | }; 86 | 87 | ll diameter(Tree tree) { 88 | ll n = tree.list.size() + 1; 89 | vbl visited(n + 1, false); 90 | vll distances(n + 1, -1); 91 | queue q; 92 | q.push({tree.root->index, 0}); 93 | ll node_max = tree.root->index, distance_max = 0; 94 | while (!q.empty()) { 95 | auto node = q.front(); 96 | q.pop(); 97 | if (node.second < distance_max) { 98 | distance_max = node.second; 99 | node_max = node.first; 100 | } 101 | 102 | for (auto neighbor : tree.list[node.first].adjacent) { 103 | if (!visited[neighbor->index]) { 104 | auto d = node.second + 1; 105 | q.push({neighbor->index, d}); 106 | visited[neighbor->index] = 1; 107 | } 108 | } 109 | } 110 | visited = vbl(n + 1, false); 111 | q.push({node_max, 0}); 112 | distance_max = 0; 113 | while (!q.empty()) { 114 | auto node = q.front(); 115 | q.pop(); 116 | maximize(distance_max, node.second); 117 | for (auto neighbor : tree.list[node.first].adjacent) { 118 | if (!visited[neighbor->index]) { 119 | auto d = node.second + 1; 120 | q.push({neighbor->index, d}); 121 | visited[neighbor->index] = 1; 122 | } 123 | } 124 | } 125 | } 126 | 127 | class CentroidTree : public Tree { 128 | private: 129 | vector __visited; 130 | vector __dir_parents, __subtree_size; 131 | Tree base; 132 | 133 | void __dfs_centroid(int node) { 134 | __subtree_size[node] = 1; 135 | for (Node *next : base.list[node].adjacent) 136 | if (!__visited[next->index] && next->index != __dir_parents[node]) { 137 | __dir_parents[next->index] = node; 138 | __dfs_centroid(next->index); 139 | __subtree_size[node] += __subtree_size[next->index]; 140 | } 141 | } 142 | 143 | int __get_centroid(int x) { 144 | __dir_parents[x] = 0; 145 | __dfs_centroid(x); 146 | int sz = __subtree_size[x]; 147 | while (true) { 148 | pair mx = {0, 0}; 149 | for (Node *next : base.list[x].adjacent) 150 | if (!__visited[next->index] && next->index != __dir_parents[x]) 151 | mx = max(mx, {__subtree_size[next->index], next->index}); 152 | if (mx.first * 2 > sz) 153 | x = mx.second; 154 | else 155 | return x; 156 | } 157 | } 158 | 159 | void __build_centroid(int node, Node *parent) { 160 | node = __get_centroid(node); 161 | list[node].parent = parent; 162 | __visited[node] = true; 163 | for (Node *next : base.list[node].adjacent) 164 | if (!__visited[next->index]) 165 | __build_centroid(next->index, &list[node]); 166 | } 167 | 168 | public: 169 | CentroidTree(Tree &tree) : Tree((int)tree.list.size()) { 170 | __visited = vector(tree.list.size()); 171 | __subtree_size = vector(tree.list.size()); 172 | __dir_parents = vector(tree.list.size()); 173 | base = tree; 174 | __build_centroid(0, nullptr); 175 | for (auto el : list) { 176 | if (el.parent == nullptr) 177 | root = &list[el.index]; 178 | else 179 | add_edge(el.index, el.parent->index); 180 | } 181 | __build(root); 182 | } 183 | }; 184 | 185 | ll diameter(Tree tree) { 186 | ll n = tree.list.size() + 1; 187 | vbl visited(n + 1, false); 188 | vll distances(n + 1, -1); 189 | queue q; 190 | q.push({tree.root->index, 0}); 191 | ll node_max = tree.root->index, distance_max = 0; 192 | while (!q.empty()) { 193 | auto node = q.front(); 194 | q.pop(); 195 | if (node.second < distance_max) { 196 | distance_max = node.second; 197 | node_max = node.first; 198 | } 199 | for (auto neighbor : tree.list[node.first].adjacent) { 200 | if (!visited[neighbor->index]) { 201 | auto d = node.second + 1; 202 | q.push({neighbor->index, d}); 203 | visited[neighbor->index] = 1; 204 | } 205 | } 206 | } 207 | visited = vbl(n + 1, false); 208 | q.push({node_max, 0}); 209 | distance_max = 0; 210 | while (!q.empty()) { 211 | auto node = q.front(); 212 | q.pop(); 213 | distance_max = max(distance_max, node.second); 214 | for (auto neighbor : tree.list[node.first].adjacent) { 215 | if (!visited[neighbor->index]) { 216 | auto d = node.second + 1; 217 | q.push({neighbor->index, d}); 218 | visited[neighbor->index] = 1; 219 | } 220 | } 221 | } 222 | } 223 | 224 | #endif // CODE_TREE_H 225 | -------------------------------------------------------------------------------- /code/Trie.hpp: -------------------------------------------------------------------------------- 1 | #include "../ref/template.hpp" 2 | 3 | struct node { 4 | vector children; 5 | int cnt; 6 | node(int alphabets) { 7 | children.resize(alphabets, nullptr); 8 | cnt = 0; 9 | } 10 | }; 11 | class Trie { 12 | node* root; 13 | int total_nodes; 14 | int alphabets; 15 | char base_char; 16 | 17 | public: 18 | node* create_node() { 19 | node* new_node = new node(this->alphabets); 20 | return new_node; 21 | } 22 | Trie(int alphabets = 26, char base_char = 'a') { 23 | this->total_nodes = 0; 24 | this->alphabets = alphabets; 25 | this->root = create_node(); 26 | this->base_char = base_char; 27 | } 28 | void insert(string& str) { 29 | node* ptr = this->root; 30 | ptr->cnt++; 31 | for (auto it : str) { 32 | int p = it - this->base_char; 33 | if (ptr->children[p] == nullptr) { 34 | ptr->children[p] = create_node(); 35 | this->total_nodes++; 36 | } 37 | ptr = ptr->children[p]; 38 | ptr->cnt++; 39 | } 40 | } 41 | bool isleaf(node* ptr) { 42 | int c = 0; 43 | for (int i = 0; i < this->alphabets; i++) { 44 | if (ptr->children[i] != nullptr) 45 | return false; 46 | c += ptr->children[i]->cnt; 47 | } 48 | if (c < ptr->cnt) 49 | return true; 50 | else { 51 | return false; 52 | } 53 | } 54 | bool search(string& str) { 55 | node* ptr = this->root; 56 | for (auto it : str) { 57 | int p = it - this->base_char; 58 | if (ptr->children[p] == nullptr) 59 | return false; 60 | ptr = ptr->children[p]; 61 | } 62 | if (this->isleaf(ptr)) 63 | return true; 64 | return false; 65 | } 66 | void insert(int x, int bits, int reverse = true) { 67 | string str; 68 | if (reverse) { 69 | for (int i = bits - 1; i >= 0; i--) { 70 | if ((x & (1ll << i)) > 0) { 71 | str.pb('1'); 72 | } else 73 | str.pb('0'); 74 | } 75 | } else { 76 | for (int i = 0; i < bits; i++) { 77 | if ((x & (1ll << i) > 0)) { 78 | str.pb('1'); 79 | } else 80 | str.pb('0'); 81 | } 82 | } 83 | this->insert(str); 84 | } 85 | int minimum(int x, int bits) { 86 | node* ptr = this->root; 87 | int ans = 0; 88 | for (int i = bits - 1; i >= 0; i--) { 89 | if ((x & (1ll << i)) > 0) { 90 | if (ptr->children[1] != nullptr) { 91 | ptr = ptr->children[1]; 92 | } else { 93 | ans += (1ll << i); 94 | ptr = ptr->children[0]; 95 | } 96 | 97 | } else { 98 | if (ptr->children[0] != nullptr) { 99 | ptr = ptr->children[0]; 100 | } else { 101 | ans += (1ll << i); 102 | ptr = ptr->children[1]; 103 | } 104 | } 105 | } 106 | return ans; 107 | } 108 | int maximum(int x, int bits) { 109 | node* ptr = this->root; 110 | int ans = 0; 111 | for (int i = bits - 1; i >= 0; i--) { 112 | if ((x & (1ll << i)) > 0) { 113 | if (ptr->children[0] != nullptr) { 114 | ans += (1ll << i); 115 | ptr = ptr->children[0]; 116 | } else { 117 | ptr = ptr->children[1]; 118 | } 119 | 120 | } else { 121 | if (ptr->children[1] != nullptr) { 122 | ans += (1ll << i); 123 | ptr = ptr->children[1]; 124 | } else { 125 | ptr = ptr->children[0]; 126 | } 127 | } 128 | } 129 | return ans; 130 | } 131 | }; -------------------------------------------------------------------------------- /img/heavy-light-decomposition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/img/heavy-light-decomposition.png -------------------------------------------------------------------------------- /img/iiit-logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/img/iiit-logo.jpeg -------------------------------------------------------------------------------- /notebook.out: -------------------------------------------------------------------------------- 1 | \BOOKMARK [0][-]{chapter.1}{Probability}{}% 1 2 | \BOOKMARK [1][-]{section.1.1}{Methods of Solving Problems}{chapter.1}% 2 3 | \BOOKMARK [1][-]{section.1.2}{Problems and Solutions}{chapter.1}% 3 4 | \BOOKMARK [2][-]{subsection.1.2.1}{Codeforces 100371-H: Granite of Science}{section.1.2}% 4 5 | \BOOKMARK [0][-]{chapter.2}{Heaps}{}% 5 6 | \BOOKMARK [1][-]{section.2.1}{Question Patterns}{chapter.2}% 6 7 | \BOOKMARK [2][-]{subsection.2.1.1}{Generic Types}{section.2.1}% 7 8 | \BOOKMARK [2][-]{subsection.2.1.2}{Specific Illustrations}{section.2.1}% 8 9 | \BOOKMARK [1][-]{section.2.2}{Elementary Theory}{chapter.2}% 9 10 | \BOOKMARK [2][-]{subsection.2.2.1}{Basic Operations}{section.2.2}% 10 11 | \BOOKMARK [2][-]{subsection.2.2.2}{Implementation Code}{section.2.2}% 11 12 | \BOOKMARK [0][-]{chapter.3}{Range Queries}{}% 12 13 | \BOOKMARK [1][-]{section.3.1}{Square Root Decomposition}{chapter.3}% 13 14 | \BOOKMARK [2][-]{subsection.3.1.1}{Motivating Examples}{section.3.1}% 14 15 | \BOOKMARK [1][-]{section.3.2}{Mo's Algorithm}{chapter.3}% 15 16 | \BOOKMARK [1][-]{section.3.3}{Segment Trees}{chapter.3}% 16 17 | \BOOKMARK [2][-]{subsection.3.3.1}{Iterative Implementation}{section.3.3}% 17 18 | \BOOKMARK [0][-]{chapter.4}{Dynamic Programming}{}% 18 19 | \BOOKMARK [1][-]{section.4.1}{Matrix Exponentiation}{chapter.4}% 19 20 | \BOOKMARK [1][-]{section.4.2}{Bitmasks}{chapter.4}% 20 21 | \BOOKMARK [2][-]{subsection.4.2.1}{Classical Bitmasks}{section.4.2}% 21 22 | \BOOKMARK [2][-]{subsection.4.2.2}{Sum over Subsets}{section.4.2}% 22 23 | \BOOKMARK [0][-]{chapter.5}{Game Theory}{}% 23 24 | \BOOKMARK [1][-]{section.5.1}{NIM Games and Sprague-Grundy Theorem}{chapter.5}% 24 25 | \BOOKMARK [1][-]{section.5.2}{Take Away Games}{chapter.5}% 25 26 | \BOOKMARK [2][-]{subsection.5.2.1}{Identifying the Losing States}{section.5.2}% 26 27 | \BOOKMARK [2][-]{subsection.5.2.2}{A few Example Functions}{section.5.2}% 27 28 | \BOOKMARK [2][-]{subsection.5.2.3}{Winning Strategy}{section.5.2}% 28 29 | \BOOKMARK [2][-]{subsection.5.2.4}{Proof of Victory}{section.5.2}% 29 30 | \BOOKMARK [2][-]{subsection.5.2.5}{References}{section.5.2}% 30 31 | \BOOKMARK [1][-]{section.5.3}{Finding Invarients}{chapter.5}% 31 32 | \BOOKMARK [0][-]{chapter.6}{Mathematical Tools}{}% 32 33 | \BOOKMARK [1][-]{section.6.1}{Fast Fourier Transforms}{chapter.6}% 33 34 | \BOOKMARK [2][-]{subsection.6.1.1}{Motivation and Purpose}{section.6.1}% 34 35 | \BOOKMARK [2][-]{subsection.6.1.2}{Algorithm}{section.6.1}% 35 36 | \BOOKMARK [2][-]{subsection.6.1.3}{Some Mathematical Representations}{section.6.1}% 36 37 | \BOOKMARK [2][-]{subsection.6.1.4}{Inverse Fourier Transform}{section.6.1}% 37 38 | \BOOKMARK [2][-]{subsection.6.1.5}{Number Theoretic Transforms}{section.6.1}% 38 39 | \BOOKMARK [2][-]{subsection.6.1.6}{Code Sample}{section.6.1}% 39 40 | \BOOKMARK [1][-]{section.6.2}{Group Theory}{chapter.6}% 40 41 | \BOOKMARK [2][-]{subsection.6.2.1}{Burnside's Lemma}{section.6.2}% 41 42 | \BOOKMARK [1][-]{section.6.3}{Number Theory}{chapter.6}% 42 43 | \BOOKMARK [2][-]{subsection.6.3.1}{Stern-Brocot Tree}{section.6.3}% 43 44 | \BOOKMARK [2][-]{subsection.6.3.2}{Chinese Remainder Theorem}{section.6.3}% 44 45 | \BOOKMARK [2][-]{subsection.6.3.3}{Mobius Inversions}{section.6.3}% 45 46 | \BOOKMARK [0][-]{chapter.7}{Graphs and Tree}{}% 46 47 | \BOOKMARK [1][-]{section.7.1}{Trees}{chapter.7}% 47 48 | \BOOKMARK [2][-]{subsection.7.1.1}{Heavy Light Decomposition}{section.7.1}% 48 49 | \BOOKMARK [1][-]{section.7.2}{Basic Algorithms on Graphs}{chapter.7}% 49 50 | \BOOKMARK [2][-]{subsection.7.2.1}{List of algorithms}{section.7.2}% 50 51 | \BOOKMARK [2][-]{subsection.7.2.2}{Code}{section.7.2}% 51 52 | \BOOKMARK [0][-]{chapter.8}{Flow Algorithms}{}% 52 53 | \BOOKMARK [1][-]{section.8.1}{Some interesting types of Flows}{chapter.8}% 53 54 | \BOOKMARK [2][-]{subsection.8.1.1}{Circulation Flows}{section.8.1}% 54 55 | \BOOKMARK [1][-]{section.8.2}{Chains in Posets}{chapter.8}% 55 56 | \BOOKMARK [0][-]{chapter.9}{Problem Solving Strategies}{}% 56 57 | \BOOKMARK [1][-]{section.9.1}{General Advice and Basic Patters}{chapter.9}% 57 58 | \BOOKMARK [1][-]{section.9.2}{Standard Problems for Practice}{chapter.9}% 58 59 | \BOOKMARK [2][-]{subsection.9.2.1}{Math and Geometry}{section.9.2}% 59 60 | \BOOKMARK [1][-]{section.9.3}{Trees and Graphs}{chapter.9}% 60 61 | -------------------------------------------------------------------------------- /notebook.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/notebook.pdf -------------------------------------------------------------------------------- /notebook.tex: -------------------------------------------------------------------------------- 1 | \documentclass{book} 2 | 3 | \usepackage{amsmath} 4 | \usepackage{amssymb} 5 | \usepackage{chemfig} 6 | \usepackage{mathtools} 7 | \usepackage{listings} 8 | \usepackage{wrapfig} 9 | \usepackage{color} 10 | \usepackage{float} 11 | \usepackage{caption} 12 | \usepackage{subcaption} 13 | \usepackage{multicol} 14 | \usepackage{paralist} 15 | \usepackage{tcolorbox} 16 | \usepackage{braket} 17 | \usepackage[framemethod=TikZ]{mdframed} 18 | \usepackage[english]{babel} 19 | \usepackage[utf8x]{inputenc} 20 | \usepackage[colorinlistoftodos]{todonotes} 21 | \usepackage{esint} 22 | \usepackage{hyperref} 23 | 24 | \title{Algorithmic Theory} 25 | \date{2019-01-01} 26 | \author{Animesh Sinha; Gaurang Tandon; Arpan Dasgupta; } 27 | 28 | \lstdefinestyle{shared}{ 29 | belowcaptionskip=1\baselineskip, 30 | breaklines=true, 31 | xleftmargin=\parindent, 32 | showstringspaces=false, 33 | basicstyle=\fontsize{10}{6}\ttfamily, 34 | } 35 | \lstdefinestyle{cpp}{ 36 | style=shared, 37 | language=C++, 38 | keywordstyle=\bfseries\color{green!40!black}, 39 | commentstyle=\itshape\color{red!80!black}, 40 | identifierstyle=\color{blue}, 41 | stringstyle=\color{purple!40!black}, 42 | } 43 | \lstdefinestyle{java}{ 44 | style=shared, 45 | language=Java, 46 | keywordstyle=\bfseries\color{green!40!black}, 47 | commentstyle=\itshape\color{purple!40!black}, 48 | identifierstyle=\color{blue}, 49 | stringstyle=\color{orange}, 50 | } 51 | \lstdefinestyle{py}{ 52 | style=shared, 53 | language=Python, 54 | keywordstyle=\bfseries\color{green!40!black}, 55 | commentstyle=\itshape\color{purple!40!black}, 56 | identifierstyle=\color{blue}, 57 | stringstyle=\color{orange}, 58 | } 59 | \lstdefinestyle{txt}{ 60 | style=shared, 61 | } 62 | \lstset{escapechar=@} 63 | 64 | \newcounter{theo}[section]\setcounter{theo}{0} 65 | \renewcommand{\thetheo}{\arabic{section}.\arabic{theo}} 66 | \newenvironment{theorem}[2][]{% 67 | \refstepcounter{theo}% 68 | \ifstrempty{#1}% 69 | {\mdfsetup{% 70 | frametitle={% 71 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 72 | \node[anchor=east,rectangle,fill=blue!20] 73 | {\strut Theorem~\thetheo};}} 74 | }% 75 | {\mdfsetup{% 76 | frametitle={% 77 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 78 | \node[anchor=east,rectangle,fill=blue!20] 79 | {\strut Theorem~\thetheo:~#1};}}% 80 | }% 81 | \mdfsetup{innertopmargin=10pt,linecolor=blue!20,% 82 | linewidth=2pt,topline=true,% 83 | frametitleaboveskip=\dimexpr-\ht\strutbox\relax 84 | } 85 | \begin{mdframed}[]\relax% 86 | \label{#2}}{\end{mdframed}} 87 | 88 | 89 | \newcounter{prf}[section]\setcounter{prf}{0} 90 | \renewcommand{\theprf}{\arabic{section}.\arabic{prf}} 91 | \newenvironment{proof}[2][]{% 92 | \refstepcounter{prf}% 93 | \ifstrempty{#1}% 94 | {\mdfsetup{% 95 | frametitle={% 96 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 97 | \node[anchor=east,rectangle,fill=red!20] 98 | {\strut Proof~\theprf};}} 99 | }% 100 | {\mdfsetup{% 101 | frametitle={% 102 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 103 | \node[anchor=east,rectangle,fill=red!20] 104 | {\strut Proof~\thetheo:~#1};}}% 105 | }% 106 | \mdfsetup{innertopmargin=10pt,linecolor=red!20,% 107 | linewidth=2pt,topline=true,% 108 | frametitleaboveskip=\dimexpr-\ht\strutbox\relax 109 | } 110 | \begin{mdframed}[]\relax% 111 | \label{#2}}{\end{mdframed}} 112 | 113 | 114 | \newcounter{prob}[section]\setcounter{prob}{0} 115 | \renewcommand{\theprob}{\arabic{section}.\arabic{prob}} 116 | \newenvironment{problem}[2][]{% 117 | \refstepcounter{prob}% 118 | \ifstrempty{#1}% 119 | {\mdfsetup{% 120 | frametitle={% 121 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 122 | \node[anchor=east,rectangle,fill=red!80] 123 | {\strut Problem~\theprob};}} 124 | }% 125 | {\mdfsetup{% 126 | frametitle={% 127 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 128 | \node[anchor=east,rectangle,fill=red!80] 129 | {\strut Problem~\theprob:~#1};}}% 130 | }% 131 | \mdfsetup{innertopmargin=10pt,linecolor=red!80,% 132 | linewidth=2pt,topline=true,% 133 | frametitleaboveskip=\dimexpr-\ht\strutbox\relax 134 | } 135 | \begin{mdframed}[]\relax% 136 | \label{#2}}{\end{mdframed}} 137 | 138 | 139 | \newcounter{exm}[section]\setcounter{exm}{0} 140 | \renewcommand{\theexm}{\arabic{section}.\arabic{exm}} 141 | \newenvironment{example}[2][]{% 142 | \refstepcounter{exm}% 143 | \ifstrempty{#1}% 144 | {\mdfsetup{% 145 | frametitle={% 146 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 147 | \node[anchor=east,rectangle,fill=green!20] 148 | {\strut Example~\theexm};}} 149 | }% 150 | {\mdfsetup{% 151 | frametitle={% 152 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 153 | \node[anchor=east,rectangle,fill=green!20] 154 | {\strut Example~\thetheo:~#1};}}% 155 | }% 156 | \mdfsetup{innertopmargin=10pt,linecolor=green!20,% 157 | linewidth=2pt,topline=true,% 158 | frametitleaboveskip=\dimexpr-\ht\strutbox\relax 159 | } 160 | \begin{mdframed}[]\relax% 161 | \label{#2}}{\end{mdframed}} 162 | 163 | 164 | \newcounter{def}[section]\setcounter{def}{0} 165 | \renewcommand{\thedef}{\arabic{section}.\arabic{def}} 166 | \newenvironment{definition}[2][]{% 167 | \refstepcounter{def}% 168 | \ifstrempty{#1}% 169 | {\mdfsetup{% 170 | frametitle={% 171 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 172 | \node[anchor=east,rectangle,fill=yellow!20] 173 | {\strut Definition~\thedef};}} 174 | }% 175 | {\mdfsetup{% 176 | frametitle={% 177 | \tikz[baseline=(current bounding box.east),outer sep=0pt] 178 | \node[anchor=east,rectangle,fill=yellow!20] 179 | {\strut Definition~\thetheo:~#1};}}% 180 | }% 181 | \mdfsetup{innertopmargin=10pt,linecolor=yellow!20,% 182 | linewidth=2pt,topline=true,% 183 | frametitleaboveskip=\dimexpr-\ht\strutbox\relax 184 | } 185 | \begin{mdframed}[]\relax% 186 | \label{#2}}{\end{mdframed}} 187 | 188 | \let\cleardoublepage\clearpage 189 | 190 | 191 | \begin{document} 192 | \pagenumbering{arabic} 193 | 194 | 195 | \begin{titlepage} 196 | \newcommand{\HRule}{\rule{\linewidth}{0.5mm}} 197 | \center 198 | \textsc{\LARGE International Institute of Information Technology, Hyderabad}\\[0.5cm] 199 | \includegraphics[scale=1]{img/iiit-logo.jpeg}\\[0.5cm] 200 | \textsc{\Large Algorithmic Theory}\\[0.5cm] 201 | \textsc{\large Data Structures, Algorithms and Competitive Programming}\\[0.5cm] % Minor heading such as course title 202 | \HRule \\[0.4cm] 203 | { \huge \bfseries College Notes}\\[0.4cm] 204 | \HRule \\[1.5cm] 205 | \begin{minipage}{0.6\textwidth} 206 | \begin{flushleft} \large 207 | \emph{Maintainers:} Animesh Sinha, Gourang Tandon, Arpan Dasgupta, Yogottam Khandelwal, Aman Kumar Singh. 208 | \end{flushleft} 209 | \end{minipage}\\[2cm] 210 | {\large \today}\\[2cm] 211 | \vfill 212 | \end{titlepage} 213 | 214 | \input{tex/probability.tex} 215 | \input{tex/stackqueueheap.tex} 216 | \input{tex/rangequeries.tex} 217 | \input{tex/dynamicprogramming.tex} 218 | \input{tex/gametheory.tex} 219 | \input{tex/mathematicaltools.tex} 220 | \input{tex/graphstrees.tex} 221 | \input{tex/flows.tex} 222 | \input{tex/_strategysheet.tex} 223 | 224 | \end{document} 225 | -------------------------------------------------------------------------------- /others/anurudh.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/others/anurudh.pdf -------------------------------------------------------------------------------- /others/berkeley.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/others/berkeley.pdf -------------------------------------------------------------------------------- /others/khattar.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/others/khattar.pdf -------------------------------------------------------------------------------- /others/stanford.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/others/stanford.pdf -------------------------------------------------------------------------------- /ques/adhoc/0339D.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * For an array of size 2^n, magic number is OR of adjacent positions (1,2), 4 | * (3,4) ... (2^n-1,2^n). then the XOR of the results, then OR and XOR 5 | * alternating at each stage till there is only 1 element left in the resultant 6 | * array. Array will have one element edited in each query, print magic number 7 | * after it. 8 | * @Reference 9 | * https://codeforces.com/contest/339/problem/D 10 | * data structures, trees, *1700 11 | */ 12 | 13 | #include 14 | #include 15 | using namespace std; 16 | 17 | #define PARENT(i) ((i - 1) / 2) 18 | #define LCHILD(i) (2 * i + 1) 19 | #define RCHILD(i) (2 * i + 2) 20 | #define POS(i) (i + (1 << n) - 1) 21 | 22 | int main() { 23 | unsigned int n, m; 24 | cin >> n >> m; 25 | unsigned int l[(1 << (n + 1)) - 1]; 26 | bool x[(1 << (n + 1)) - 1]; 27 | for (int i = 0; i < (1 << n); i++) { 28 | cin >> l[POS(i)]; 29 | x[POS(i)] = false; 30 | } 31 | for (int i = POS(0) - 1; i >= 0; i--) 32 | x[i] = !x[LCHILD(i)]; 33 | for (int i = POS(0) - 1; i >= 0; i--) 34 | l[i] = x[i] ? (l[LCHILD(i)] | l[RCHILD(i)]) 35 | : (l[LCHILD(i)] ^ l[RCHILD(i)]); 36 | while (m--) { 37 | unsigned int pos, val; 38 | cin >> pos >> val; 39 | pos--; 40 | l[POS(pos)] = val; 41 | for (unsigned int c = PARENT(POS(pos)); c != 0; c = PARENT(c)) 42 | l[c] = x[c] ? (l[LCHILD(c)] | l[RCHILD(c)]) 43 | : (l[LCHILD(c)] ^ l[RCHILD(c)]); 44 | l[0] = x[0] ? (l[LCHILD(0)] | l[RCHILD(0)]) 45 | : (l[LCHILD(0)] ^ l[RCHILD(0)]); 46 | cout << l[0] << endl; 47 | } 48 | return 0; 49 | } -------------------------------------------------------------------------------- /ques/adhoc/p2121.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * A hexadecimal representation of the walls around each cell of a maze are 4 | * given. Print the visualization of this grid. 5 | * @Reference 6 | * https://icpcarchive.ecs.baylor.edu/index.php?option=onlinejudge&page=show_problem&problem=122 7 | * implementation 8 | */ 9 | 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | enum Wall { PRESENT, ABSENT, CONFLICT }; 15 | class Cell { 16 | public: 17 | Wall top, bottom, left, right; 18 | Cell() { 19 | top = bottom = left = right = CONFLICT; 20 | } 21 | explicit Cell(int code) { 22 | top = (code & 0b0001) == 0 ? PRESENT : ABSENT; 23 | right = (code & 0b0010) == 0 ? PRESENT : ABSENT; 24 | bottom = (code & 0b0100) == 0 ? PRESENT : ABSENT; 25 | left = (code & 0b1000) == 0 ? PRESENT : ABSENT; 26 | } 27 | void pTop() { 28 | if (top == PRESENT) 29 | cout << "+---"; 30 | else if (top == ABSENT) 31 | cout << "+ "; 32 | else if (top == CONFLICT) 33 | cout << "+xxx"; 34 | } 35 | void pLeft() { 36 | if (left == PRESENT) 37 | cout << "|"; 38 | else if (left == ABSENT) 39 | cout << " "; 40 | else if (left == CONFLICT) 41 | cout << "X"; 42 | } 43 | void pBottom() { 44 | if (bottom == PRESENT) 45 | cout << "+---"; 46 | else if (bottom == ABSENT) 47 | cout << "+ "; 48 | else if (bottom == CONFLICT) 49 | cout << "+xxx"; 50 | } 51 | void pRight() { 52 | if (right == PRESENT) 53 | cout << "|"; 54 | else if (right == ABSENT) 55 | cout << " "; 56 | else if (right == CONFLICT) 57 | cout << "X"; 58 | } 59 | }; 60 | 61 | int main() { 62 | for (int i = 0;; i++) { 63 | int nr, nc, temp; 64 | cin >> nr >> nc; 65 | Cell grid[nr][nc]; 66 | if (nr == 0 && nc == 0) 67 | break; 68 | // Take the Input and initialize the Cells 69 | for (int i = 0; i < nr; i++) 70 | for (int j = 0; j < nc; j++) { 71 | cin >> hex >> temp; 72 | grid[i][j] = Cell(temp); 73 | } 74 | // Generate all the Conflicts 75 | for (int i = 0; i < nr; i++) 76 | for (int j = 0; j < nc; j++) { 77 | if (i > 0 && grid[i][j].top != grid[i - 1][j].bottom) 78 | grid[i][j].top = CONFLICT; 79 | if (j > 0 && grid[i][j].left != grid[i][j - 1].right) 80 | grid[i][j].left = CONFLICT; 81 | if (i < nr - 1 && grid[i][j].bottom != grid[i + 1][j].top) 82 | grid[i][j].bottom = CONFLICT; 83 | if (j < nc - 1 && grid[i][j].right != grid[i][j + 1].left) 84 | grid[i][j].right = CONFLICT; 85 | } 86 | // Printing out the results 87 | for (int i = 0; i < nr; i++) { 88 | for (int j = 0; j < nc; j++) 89 | grid[i][j].pTop(); 90 | cout << "+" << endl; 91 | for (int j = 0; j < nc; j++) { 92 | grid[i][j].pLeft(); 93 | cout << " "; 94 | } 95 | grid[i][nc - 1].pRight(); 96 | cout << endl; 97 | } 98 | for (int j = 0; j < nc; j++) 99 | grid[nr - 1][j].pBottom(); 100 | cout << "+" << endl; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /ques/heaps/ANUMLA.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * Sum of all subsets of a set is given, find the original set. 4 | * @Reference 5 | * https://www.codechef.com/problems/ANUMLA 6 | * cook51, easy, greedy, heap, multiset 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | int main() { 16 | int tests; 17 | cin >> tests; 18 | while (tests--) { 19 | priority_queue, greater<>> all, sum; 20 | vector result, acc; 21 | acc.push_back(0); 22 | sum.push(0); 23 | int n; 24 | cin >> n; 25 | for (int i = 0; i < (1 << n); i++) { 26 | int temp; 27 | cin >> temp; 28 | all.push(temp); 29 | } 30 | while (!all.empty()) { 31 | if (sum.empty() || all.top() != sum.top()) { 32 | int val = all.top(), size = (int)acc.size(); 33 | result.push_back(val); 34 | for (int i = 1; i < size; i++) 35 | sum.push(val + acc[i]); 36 | for (int i = 0; i < size; i++) 37 | acc.push_back(val + acc[i]); 38 | all.pop(); 39 | } else { 40 | all.pop(); 41 | sum.pop(); 42 | } 43 | } 44 | for (auto el : result) 45 | cout << el << " "; 46 | cout << endl; 47 | } 48 | } -------------------------------------------------------------------------------- /ques/heaps/IPCTRAIN.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * Given a list of teachers, each arrives on day Di, wants to take Ti classes, 4 | * and has sadness Si for each day he cannot take class. Minimize total sadness. 5 | * @Reference 6 | * https://www.codechef.com/JULY17/problems/IPCTRAIN 7 | * admin2, easy, greedy, heap, july17, stl 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | struct lecturer { 17 | long long int d, t, s; 18 | }; 19 | 20 | int main() { 21 | int tests; 22 | cin >> tests; 23 | while (tests--) { 24 | unsigned long long int n, d; 25 | cin >> n >> d; 26 | vector list(n); 27 | d++; 28 | auto compareD = [](lecturer a, lecturer b) { return a.d < b.d; }; 29 | auto compareS = [](lecturer a, lecturer b) { return a.s < b.s; }; 30 | priority_queue, decltype(compareS)> q( 31 | compareS); 32 | for (int i = 0; i < n; i++) 33 | cin >> list[i].d >> list[i].t >> list[i].s; 34 | sort(list.begin(), list.end(), compareD); 35 | for (int i = 0; i < n; i++) { 36 | q.push(list[i]); 37 | long long int reduction = 38 | ((i == n - 1) ? d : list[i + 1].d) - list[i].d; 39 | while (reduction > 0 && !q.empty()) { 40 | if (reduction < q.top().t) { 41 | lecturer copy = q.top(); 42 | copy.t -= reduction; 43 | q.pop(); 44 | q.push(copy); 45 | reduction = 0; 46 | } else { 47 | reduction -= q.top().t; 48 | q.pop(); 49 | } 50 | } 51 | } 52 | long long int sadness = 0; 53 | while (!q.empty()) { 54 | sadness += q.top().t * q.top().s; 55 | q.pop(); 56 | } 57 | cout << sadness << endl; 58 | } 59 | return 0; 60 | } -------------------------------------------------------------------------------- /ques/heaps/KSUBSUM.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * Find the Kth maximum sum of a subarray in a given array. 4 | * @Reference 5 | * https://www.codechef.com/problems/KSUBSUM 6 | * cook18, easy, flying_ant 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | vector merge(vector a, vector b, 15 | unsigned long k) { 16 | vector result(k); 17 | for (int i = 0, x = 0, y = 0; i < k; i++) { 18 | (x < a.size() && (y >= b.size() || a[x] > b[y])) ? (result[i] = a[x++]) 19 | : (result[i] = b[y++]); 20 | } 21 | return result; 22 | } 23 | 24 | int main() { 25 | ios_base::sync_with_stdio(false); 26 | cin.tie(nullptr); 27 | int tests; 28 | cin >> tests; 29 | while (tests--) { 30 | unsigned int n, k1, k2, k3; 31 | cin >> n >> k1 >> k2 >> k3; 32 | long long input[n]; 33 | for (int i = 0; i < n; i++) 34 | cin >> input[i]; 35 | long long ps[n]; 36 | ps[0] = input[0]; 37 | for (int i = 1; i < n; i++) 38 | ps[i] = ps[i - 1] + input[i]; 39 | vector maxSum(k3, INT32_MIN), minPre({0}); 40 | for (int i = 0; i < n; i++) { 41 | // Get the list of max-sums using older max-sums and current prefix 42 | // - lowest k prefixes 43 | vector sums; 44 | sums.reserve(minPre.size()); 45 | for (auto el : minPre) 46 | sums.push_back(ps[i] - el); 47 | maxSum = merge(maxSum, sums, k3); 48 | // Maintain a k size sorted array of the lowest prefixes, in 49 | // ascending order 50 | minPre.push_back(ps[i]); 51 | for (unsigned long d = minPre.size() - 1; 52 | d > 0 && minPre[d - 1] > minPre[d]; d--) { 53 | minPre[d] ^= minPre[d - 1]; 54 | minPre[d - 1] ^= minPre[d]; 55 | minPre[d] ^= minPre[d - 1]; 56 | } 57 | while (minPre.size() > k3) 58 | minPre.pop_back(); 59 | } 60 | cout << maxSum[k1 - 1] << " " << maxSum[k2 - 1] << " " << maxSum[k3 - 1] 61 | << endl; 62 | } 63 | return 0; 64 | } -------------------------------------------------------------------------------- /ques/heaps/MOSTDIST.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * With online insertion and deletion of points in a set S, find the point in S 4 | * farthest from a random queried point (x,y). 5 | * @Reference 6 | * https://www.codechef.com/problems/MOSTDIST 7 | * cook52, easy, geometry, heap, kostya_by, manhattan 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #define MAX(a, b) (a > b ? a : b) 14 | using namespace std; 15 | 16 | struct point { 17 | int x = 0, y = 0; 18 | int val = 0; 19 | point(int _x, int _y, int _val) { 20 | x = _x; 21 | y = _y; 22 | val = _val; 23 | } 24 | }; 25 | 26 | int main() { 27 | int q, ans = 0; 28 | cin >> q; 29 | vector points; 30 | auto compare = [](point a, point b) { return a.val < b.val; }; 31 | auto equals = [](point a, point b) { return a.x == b.x && a.y == b.y; }; 32 | auto distance = [](point a, point b) { 33 | return abs(a.x - b.x) + abs(a.y - b.y); 34 | }; 35 | priority_queue, decltype(compare)> ptPP(compare), 36 | delPP(compare), ptPM(compare), delPM(compare), ptMM(compare), 37 | delMM(compare), ptMP(compare), delMP(compare); 38 | while (q--) { 39 | char ch; 40 | point p(0, 0, 0); 41 | cin >> ch; 42 | switch (ch) { 43 | case '+': 44 | cin >> p.x >> p.y; 45 | p.x ^= ans; 46 | p.y ^= ans; 47 | ptPP.push(point(p.x, p.y, p.x + p.y)); 48 | ptPM.push(point(p.x, p.y, p.x - p.y)); 49 | ptMM.push(point(p.x, p.y, -p.x - p.y)); 50 | ptMP.push(point(p.x, p.y, -p.x + p.y)); 51 | points.push_back(p); 52 | break; 53 | case '-': 54 | int n; 55 | cin >> n; 56 | n ^= ans; 57 | p = points[n - 1]; 58 | delPP.push(point(p.x, p.y, p.x + p.y)); 59 | delPM.push(point(p.x, p.y, p.x - p.y)); 60 | delMM.push(point(p.x, p.y, -p.x - p.y)); 61 | delMP.push(point(p.x, p.y, -p.x + p.y)); 62 | while (!ptPP.empty() && equals(ptPP.top(), delPP.top())) { 63 | ptPP.pop(); 64 | delPP.pop(); 65 | } 66 | while (!ptPM.empty() && equals(ptPM.top(), delPM.top())) { 67 | ptPM.pop(); 68 | delPM.pop(); 69 | } 70 | while (!ptMM.empty() && equals(ptMM.top(), delMM.top())) { 71 | ptMM.pop(); 72 | delMM.pop(); 73 | } 74 | while (!ptMP.empty() && equals(ptMP.top(), delMP.top())) { 75 | ptMP.pop(); 76 | delMP.pop(); 77 | } 78 | break; 79 | case '?': 80 | cin >> p.x >> p.y; 81 | p.x ^= ans; 82 | p.y ^= ans; 83 | ans = 84 | MAX(MAX(distance(p, ptPP.top()), distance(p, ptPM.top())), 85 | MAX(distance(p, ptMM.top()), distance(p, ptMP.top()))); 86 | cout << ans << endl; 87 | break; 88 | default: 89 | return 1; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /ques/heaps/findingtherunningmedian.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * As elements keep being added to a set, keep finding it's median. 4 | * @Reference 5 | * https://www.hackerrank.com/challenges/find-the-running-median/problem 6 | * data structures, heaps, hard 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace std; 15 | 16 | int main() { 17 | unsigned int n; 18 | cin >> n; 19 | vector list(n); 20 | for (int i = 0; i < n; i++) 21 | cin >> list[i]; 22 | int top; 23 | cout << setprecision(1) << fixed; 24 | // Maintain a min-heap of elements greater than median, and max-heap of 25 | // elements less then the median. 26 | priority_queue, std::less<>> less; 27 | priority_queue, std::greater<>> more; 28 | for (int i = 0; i < n; i++) { 29 | if (i % 2 == 0) { 30 | if (!less.empty() && list[i] < less.top()) { 31 | top = less.top(); 32 | less.pop(); 33 | less.push(list[i]); 34 | } else if (!more.empty() && list[i] > more.top()) { 35 | top = more.top(); 36 | more.pop(); 37 | more.push(list[i]); 38 | } else { 39 | top = list[i]; 40 | } 41 | cout << (double)top << endl; 42 | } else { 43 | if (top > list[i]) { 44 | more.push(top); 45 | less.push(list[i]); 46 | } else { 47 | more.push(list[i]); 48 | less.push(top); 49 | } 50 | cout << ((double)less.top() + (double)more.top()) / 2 << endl; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /ques/palindromes/BINPALIN.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | typedef long long ll; 5 | typedef vector vll; 6 | typedef pair pll; 7 | typedef vector> mll; 8 | typedef vector> vpl; 9 | typedef long double ld; 10 | typedef vector vld; 11 | typedef vector> mld; 12 | typedef vector vbl; 13 | typedef vector> mbl; 14 | #define minimize(a, b) (a = min(a, b)) 15 | #define maximize(a, b) (a = max(a, b)) 16 | const long long MOD = 1e9 + 7; 17 | 18 | template 19 | istream &operator>>(istream &in, vector &vec) { 20 | ll n = vec.size(); 21 | for (int i = 0; i < n; i++) 22 | in >> vec[i]; 23 | return in; 24 | } 25 | template 26 | ostream &operator<<(ostream &out, vector &vec) { 27 | for (auto val : vec) 28 | out << val << " "; 29 | out << endl; 30 | return out; 31 | } 32 | 33 | struct PalindromicTree { 34 | const static long long MAXN = 100000; 35 | struct Node { int start, end; int length; int insert_edge[26]; int suffix_edge; }; 36 | Node root1, root2; Node tree[MAXN]; int curr_node, ptr, size; string s; 37 | 38 | void insert(int idx) { 39 | int tmp = curr_node; 40 | while (true) { 41 | int curLength = tree[tmp].length; 42 | if (idx - curLength >= 1 and s[idx] == s[idx - curLength - 1]) break; 43 | tmp = tree[tmp].suffix_edge; 44 | } 45 | if (tree[tmp].insert_edge[s[idx] - 'a'] != 0) { 46 | curr_node = tree[tmp].insert_edge[s[idx] - 'a']; return; 47 | } 48 | ptr++; 49 | tree[tmp].insert_edge[s[idx] - 'a'] = ptr; 50 | tree[ptr].length = tree[tmp].length + 2; 51 | tree[ptr].end = idx; 52 | tree[ptr].start = idx - tree[ptr].length + 1; 53 | tmp = tree[tmp].suffix_edge; 54 | curr_node = ptr; 55 | if (tree[curr_node].length == 1) { tree[curr_node].suffix_edge = 2; return; } 56 | while (true) { 57 | int cur_length = tree[tmp].length; 58 | if (idx - cur_length >= 1 and s[idx] == s[idx - cur_length - 1]) break; 59 | tmp = tree[tmp].suffix_edge; 60 | } 61 | tree[curr_node].suffix_edge = tree[tmp].insert_edge[s[idx] - 'a']; 62 | } 63 | PalindromicTree(string st) { 64 | root1.length = -1, root1.suffix_edge = 1, root2.length = 0, 65 | root2.suffix_edge = 1, tree[1] = root1, tree[2] = root2, ptr = 2; 66 | curr_node = 1, s = st, size = st.size(); 67 | for (int i = 0; i < size; i++) insert(i); 68 | } 69 | vpl get_palindromes() { 70 | vpl res(ptr - 2); 71 | for (int i = 3; i <= ptr; i++) res[i - 2] = {tree[i].start, tree[i].end}; 72 | return res; 73 | } 74 | }; 75 | 76 | int main() { 77 | ios_base::sync_with_stdio(false); 78 | cin.tie(nullptr); 79 | cout.tie(nullptr); 80 | int n; cin >> n; 81 | PalindromicTree(""); 82 | while (n--) { 83 | 84 | } 85 | } -------------------------------------------------------------------------------- /ques/rare/ADAMTR.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * See if flipping ith row with ith column can convert one matrix to another 4 | * given matrix. 5 | * @Reference 6 | * https://www.codechef.com/problems/ADAMTR 7 | * 2-SAT, math, matrices 8 | */ 9 | 10 | #include 11 | using namespace std; 12 | 13 | int main() { 14 | int t; 15 | cin >> t; 16 | while (t--) { 17 | int n; 18 | cin >> n; 19 | int matA[n][n], matB[n][n]; 20 | bool swap[n][n], solvable = true; 21 | for (int i = 0; i < n; i++) 22 | for (int j = 0; j < n; j++) 23 | cin >> matA[i][j]; 24 | for (int i = 0; i < n; i++) 25 | for (int j = 0; j < n; j++) 26 | cin >> matB[i][j]; 27 | for (int i = 0; i < n; i++) { 28 | for (int j = i; j < n; j++) { 29 | if (matA[i][j] == matB[i][j] && matA[j][i] == matB[j][i]) 30 | swap[i][j] = swap[j][i] = false; 31 | else if (matA[i][j] == matB[j][i] && matA[j][i] == matB[i][j]) 32 | swap[i][j] = swap[j][i] = true; 33 | else 34 | solvable = false; 35 | } 36 | } 37 | if (!solvable) { 38 | cout << "No" << endl; 39 | continue; 40 | } 41 | bool flip[n], ans = true; 42 | flip[0] = false; 43 | for (int i = 0; i < n; i++) 44 | flip[i] = (swap[0][i] != flip[0]); 45 | for (int i = 0; i < n; i++) 46 | for (int j = 0; j < n; j++) 47 | if (swap[i][j] == (flip[i] == flip[j])) 48 | ans = false; 49 | cout << (ans ? "Yes" : "No") << endl; 50 | } 51 | } -------------------------------------------------------------------------------- /ques/segtree/380C.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * For any (l,r), let S = (((a & b) ^ (a | b)) & (a ^ b)), where a is minimum 4 | * and b is second minimum. Print the maximum possible value of S for any (l,r) 5 | * @Reference 6 | * https://www.hackerrank.com/challenges/and-xor-or/problem 7 | * segtree, brackets 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | template 17 | class SegmentTree { 18 | private: 19 | vector data; 20 | unsigned long size; 21 | inline unsigned long parent(unsigned long i) { 22 | return i >> 1; 23 | } 24 | inline unsigned long lChild(unsigned long i) { 25 | return i << 1; 26 | } 27 | inline unsigned long rChild(unsigned long i) { 28 | return i << 1 | 1; 29 | } 30 | inline unsigned long sibling(unsigned long i) { 31 | return i ^ 1; 32 | } 33 | inline unsigned long element(unsigned long i) { 34 | return i + size; 35 | } 36 | inline bool isRoot(unsigned long i) { 37 | return i == 1; 38 | } 39 | inline bool islChild(unsigned long i) { 40 | return (i & 1) == 0; 41 | } 42 | inline bool isrChild(unsigned long i) { 43 | return (i & 1) != 0; 44 | } 45 | function operation; 46 | Type defaultValue; 47 | 48 | public: 49 | explicit SegmentTree(const vector &list, 50 | function segOperation, 51 | Type defaultTo) { 52 | size = (1ul << (long)ceil(log2(list.size()))); 53 | data = vector(size * 2, defaultTo); 54 | defaultValue = defaultTo; 55 | operation = segOperation; 56 | for (unsigned long i = 0; i < list.size(); i++) 57 | data[i + size] = list[i]; 58 | for (unsigned long i = size - 1; i > 0; --i) 59 | data[i] = operation(data[lChild(i)], data[rChild(i)]); 60 | } 61 | void modify(unsigned long position, Type value) { 62 | data[element(position)] = value; 63 | for (data[position = element(position)]; !isRoot(position); 64 | position = parent(position)) { 65 | if (islChild(position)) 66 | data[parent(position)] = 67 | operation(data[position], data[sibling(position)]); 68 | if (isrChild(position)) 69 | data[parent(position)] = 70 | operation(data[sibling(position)], data[position]); 71 | } 72 | } 73 | Type query(unsigned long l, unsigned long r) { 74 | Type lAccumulator = defaultValue, rAccumulator = defaultValue; 75 | for (l = element(l), r = element(r); l < r; 76 | l = parent(l), r = parent(r)) { 77 | if (isrChild(l)) { 78 | lAccumulator = operation(lAccumulator, data[l++]); 79 | } 80 | if (isrChild(r)) { 81 | rAccumulator = operation(data[--r], rAccumulator); 82 | } 83 | } 84 | return operation(lAccumulator, rAccumulator); 85 | } 86 | }; 87 | 88 | class Node { 89 | public: 90 | enum Type { OPEN = '(', CLOSE = ')', EXPRESSION = '.' }; 91 | long long total, open, close; 92 | explicit Node() { 93 | total = open = close = 0; 94 | } 95 | explicit Node(Type bracket) { 96 | total = 0; 97 | if (bracket == OPEN) { 98 | open = 1; 99 | close = 0; 100 | } else if (bracket == CLOSE) { 101 | open = 0; 102 | close = 1; 103 | } else { 104 | open = 0; 105 | close = 0; 106 | } 107 | } 108 | static Node merge(Node a, Node b) { 109 | long long temp = min(a.open, b.close); 110 | Node c(EXPRESSION); 111 | c.total = a.total + b.total + temp; 112 | c.open = a.open + b.open - temp; 113 | c.close = a.close + b.close - temp; 114 | return c; 115 | } 116 | }; 117 | 118 | int main() { 119 | string st; 120 | cin >> st; 121 | vector list; 122 | for (char ch : st) 123 | list.emplace_back(ch == '(' ? Node::OPEN : Node::CLOSE); 124 | SegmentTree tree(list, Node::merge, *(new Node)); 125 | int q; 126 | cin >> q; 127 | while (q--) { 128 | unsigned long l, r; 129 | cin >> l >> r; 130 | cout << tree.query(l - 1, r).total * 2 << endl; 131 | } 132 | } -------------------------------------------------------------------------------- /ques/stacks/0005C.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * In a Sequence of Open and Closed Brackets, Identify the longest 4 | * well-bracketed subsequence and count the total number of Disjoint 5 | * well-bracketed subsequences. 6 | * @Reference 7 | * https://codeforces.com/contest/5/problem/C 8 | * constructive algorithms, data structures, dp, greedy, sorting, strings, *1900 9 | */ 10 | 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | int main() { 16 | string input; 17 | cin >> input; 18 | input = '-' + input; 19 | stack st; 20 | st.push(0); 21 | for (int i = 1; i < input.length(); i++) { 22 | if (input[i] == '(') { 23 | st.push(i); 24 | } else if (input[i] == ')') { 25 | (input[st.top()] == '(') ? st.pop() : st.push(i); 26 | } 27 | } 28 | st.push((int)input.length()); 29 | int count = 1, length = 0; 30 | while (st.size() > 1) { 31 | int l = st.top(); 32 | st.pop(); 33 | l -= st.top() + 1; 34 | if (length < l) { 35 | length = l; 36 | count = 1; 37 | } else if (length == l && l > 0) { 38 | count++; 39 | } 40 | } 41 | cout << length << " " << count << endl; 42 | } -------------------------------------------------------------------------------- /ques/stacks/0281D.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * For any subarray (l,r) let x be the XOR of maximum two numbers. 4 | * Find the maximum of all such x's for any subarray in the given array. 5 | * @Reference 6 | * https://codeforces.com/contest/281/problem/D 7 | * two pointers, *2000 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | int main() { 16 | // Input Segment 17 | unsigned long long n, r = 0; 18 | cin >> n; 19 | vector list(n); 20 | for (int i = 0; i < n; i++) 21 | cin >> list[i]; 22 | // Finding the result from Left to Right (If max comes after second max) 23 | stack st; 24 | for (auto item : list) { 25 | while (!st.empty() && st.top() < item) { 26 | r = max(r, item ^ st.top()); 27 | st.pop(); 28 | } 29 | st.push(item); 30 | } 31 | // Finding the result from Right to Left (If max comes before second max) 32 | st.empty(); 33 | for (int i = 0; i < list.size() / 2; i++) 34 | swap(list[i], list[list.size() - 1 - i]); 35 | for (int i = 0; i < n; i++) { 36 | while (!st.empty() && st.top() < list[i]) { 37 | r = max(r, list[i] ^ st.top()); 38 | st.pop(); 39 | } 40 | st.push(list[i]); 41 | } 42 | // Output Result 43 | cout << r << endl; 44 | } -------------------------------------------------------------------------------- /ques/stacks/0343B.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * For two wires entangled with each other, given which one is on top after 4 | * every loop, Figure out whether they can be disentangled. 5 | * @Reference 6 | * https://codeforces.com/contest/343/problem/B 7 | * data structures, greedy, implementation, *1600 8 | */ 9 | 10 | #include 11 | #include 12 | using namespace std; 13 | 14 | int main() { 15 | stack st; 16 | string input; 17 | cin >> input; 18 | for (char i : input) { 19 | if (st.empty() || st.top() != i) 20 | st.push(i); 21 | else 22 | st.pop(); 23 | } 24 | cout << (st.empty() ? "Yes" : "No") << endl; 25 | } -------------------------------------------------------------------------------- /ques/stacks/andxoror.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * For any (l,r), let S = (((a & b) ^ (a | b)) & (a ^ b)), where a is minimum 4 | * and b is second minimum. Print the maximum possible value of S for any (l,r) 5 | * @Reference 6 | * https://www.hackerrank.com/challenges/and-xor-or/problem 7 | * stacks, medium, histogram 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | long long int EXPR(long long int a, long long int b) { 16 | return (((a & b) ^ (a | b)) & (a ^ b)); 17 | } 18 | 19 | int main() { 20 | // Input Segment 21 | long long n, r = INT32_MIN; 22 | cin >> n; 23 | vector list((unsigned)n); 24 | for (int i = 0; i < n; i++) 25 | cin >> list[i]; 26 | // Finding the result from Left to Right (If max comes after second max) 27 | stack st; 28 | for (auto item : list) { 29 | while (!st.empty() && st.top() > item) { 30 | r = max(r, EXPR(item, st.top())); 31 | st.pop(); 32 | } 33 | st.push(item); 34 | } 35 | // Finding the result from Right to Left (If max comes before second max) 36 | st.empty(); 37 | for (int i = 0; i < list.size() / 2; i++) 38 | swap(list[i], list[list.size() - 1 - i]); 39 | for (auto item : list) { 40 | while (!st.empty() && st.top() > item) { 41 | r = max(r, EXPR(item, st.top())); 42 | st.pop(); 43 | } 44 | st.push(item); 45 | } 46 | // Output Result 47 | cout << r << endl; 48 | } -------------------------------------------------------------------------------- /ques/stacks/poisonousplants.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * @Problem 3 | * Given an array, after each iteration all elements with smaller values to 4 | * immediate left get deleted. Find the number of iterations before there are no 5 | * more deletions. 6 | * @Reference 7 | * https://www.hackerrank.com/challenges/poisonous-plants/problem 8 | * stacks, hard 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #define MAX(a, b) (a > b ? a : b) 16 | using namespace std; 17 | struct X { 18 | long long val, shot; 19 | explicit X(long long n = 0, long long s = 0) { 20 | this->val = n; 21 | this->shot = s; 22 | } 23 | }; 24 | 25 | int main() { 26 | unsigned int n; 27 | cin >> n; 28 | vector list(n); 29 | for (int i = 0; i < n; i++) 30 | cin >> list[i]; 31 | reverse(list.begin(), list.end()); 32 | stack st; 33 | long count = 0, max = 0; 34 | for (auto el : list) { 35 | for (count = 0; !st.empty() && st.top().val > el;) { 36 | count += MAX(st.top().shot - count, 1); 37 | st.pop(); 38 | } 39 | st.push(X(el, count)); 40 | max = MAX(max, count); 41 | } 42 | cout << max << endl; 43 | } -------------------------------------------------------------------------------- /ref/DisjointSets.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | struct DisjointSetTree { 4 | ll comp_count; vll parent, comp_size; set roots; 5 | DisjointSetTree(int n) { 6 | comp_count = n; parent.resize(n); comp_size.resize(n, 1); 7 | iota(parent.begin(), parent.end(), 0); 8 | for (int i = 0; i < n; i++) roots.insert(i); 9 | } 10 | int find(int u) { 11 | if (parent[u] == u) return parent[u]; 12 | return parent[u] = find(parent[u]); 13 | } 14 | bool merge(int u, int v) { 15 | u = find(u), v = find(v); if (u == v) return false; 16 | parent[u] = v; comp_size[v] += comp_size[u]; comp_size[u] = 0; 17 | roots.erase(u); comp_count--; return true; 18 | } 19 | }; 20 | 21 | class DynamicConnectivity { 22 | void __dfs(int v, int l, int r, vector& res) { 23 | long long last_ans = answer; 24 | int state = save_ptr; 25 | for (auto query : tree[v]) merge(query); 26 | if (l == r - 1) res[l] = answer; 27 | else { 28 | int m = (l + r) / 2; 29 | __dfs(v * 2 + 1, l, m, res); 30 | __dfs(v * 2 + 2, m, r, res); 31 | } 32 | while (save_ptr != state) rollback(); 33 | answer = last_ans; 34 | }; 35 | 36 | public: 37 | int size_nodes, size_query; 38 | struct Node { long long parent, comp_size = 1; }; 39 | ll answer = 0; 40 | vector data; 41 | vector saved_object; 42 | vector saved_value; 43 | int save_ptr = 0; 44 | 45 | struct Query { 46 | int u, v; 47 | Query(pair p = {0, 0}) { u = p.first, v = p.second; } 48 | }; 49 | vector> tree; 50 | DynamicConnectivity(int n = 600000, int q = 300000) { 51 | size_nodes = n, size_query = q; int tree_size = 1; 52 | while (tree_size < q) tree_size <<= 1; 53 | data = vector(n); 54 | tree = vector>(2 * tree_size); 55 | saved_object = vector(4 * q); 56 | saved_value = vector(4 * q); 57 | for (int i = 0; i < n; i++) 58 | data[i].parent = i; 59 | answer = n; // Storing the initial answer 60 | } 61 | void change(long long& x, long long y) { 62 | saved_object[save_ptr] = &x; saved_value[save_ptr] = x; 63 | x = y; save_ptr++; 64 | } 65 | void rollback() { 66 | save_ptr--; 67 | (*saved_object[save_ptr]) = saved_value[save_ptr]; 68 | } 69 | int find(int x) { 70 | if (data[x].parent == x) return x; 71 | return find(data[x].parent); 72 | } 73 | void merge(const Query& q) { 74 | int x = find(q.u); int y = find(q.v); 75 | if (x == y) return; 76 | if (data[x].comp_size < data[y].comp_size) swap(x, y); 77 | change(data[y].parent, x); 78 | change(data[x].comp_size, data[x].comp_size + data[y].comp_size); 79 | // Changing the Answer on query 80 | change(answer, answer - 1); 81 | } 82 | void add(int l, int r, Query edge, int node = 0, int x = 0, int y = -1) { 83 | if (y == -1) y = size_query; 84 | if (l >= r) return; 85 | if (l == x && r == y) tree[node].push_back(edge); 86 | else { 87 | int m = (x + y) / 2; 88 | add(l, min(r, m), edge, node * 2 + 1, x, m); 89 | add(max(m, l), r, edge, node * 2 + 2, m, y); 90 | } 91 | } 92 | vector solve(int v = 0, int l = 0, int r = -1) { 93 | if (r == -1) r = size_query; 94 | vector vec(size_query); 95 | if (size_query > 0) __dfs(v, l, r, vec); 96 | return vec; 97 | } 98 | DynamicConnectivity(int n, vector queries) : DynamicConnectivity(n, queries.size()) { 99 | map, int> last; 100 | for (int i = 0; i < size_query; i++) { 101 | pair p(queries[i].u, queries[i].v); 102 | if (last.count(p)) { add(last[p], i, queries[i]); last.erase(p); } 103 | else { last[p] = i; } 104 | } 105 | for (auto x : last) add(x.second, size_query, x.first); 106 | } 107 | }; -------------------------------------------------------------------------------- /ref/DynamicProgramming.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | class LineContainer { 4 | private: 5 | struct Line { 6 | mutable long long slope, constt, p; 7 | bool operator<(const Line &o) const { return slope < o.slope; } 8 | bool operator<(long long x) const { return p < x; } 9 | }; 10 | multiset> lines; 11 | // (for doubles, use inf = 1/.0, div(a,b) = a/b) 12 | bool __is_max_query = false; const long long inf = LLONG_MAX; 13 | long long __div(long long a, long long b) { return a / b - ((a ^ b) < 0 && a % b); } // floored division 14 | bool __intersect(multiset::iterator x, multiset::iterator y) { 15 | if (y == lines.end()) { x->p = inf; return false; } 16 | if (x->slope == y->slope) x->p = x->constt > y->constt ? inf : -inf; 17 | else x->p = __div(y->constt - x->constt, x->slope - y->slope); 18 | return x->p >= y->p; 19 | } 20 | public: 21 | LineContainer(bool is_max = false) { this->__is_max_query = is_max; } 22 | void add(long long slope, long long constt) { 23 | if (!__is_max_query) { slope = -slope; constt = -constt; } 24 | auto z = lines.insert({slope, constt, 0}), y = z++, x = y; 25 | while (__intersect(y, z)) z = lines.erase(z); 26 | if (x != lines.begin() && __intersect(--x, y)) __intersect(x, y = lines.erase(y)); 27 | while ((y = x) != lines.begin() && (--x)->p >= y->p) __intersect(x, lines.erase(y)); 28 | } 29 | long long query(long long x) { 30 | assert(!lines.empty()); 31 | auto l = *lines.lower_bound(x); 32 | return (l.slope * x + l.constt) * (__is_max_query ? 1 : -1); 33 | } 34 | }; 35 | 36 | void dp_sos(vll &arr) { 37 | const int bitsize = 20; 38 | for (int i = 0; i < bitsize; ++i) 39 | for (int mask = 0; mask < (1 << bitsize); ++mask) 40 | if (mask & (1 << i)) arr[mask] += arr[mask ^ (1 << i)]; 41 | } -------------------------------------------------------------------------------- /ref/FastFourier.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | template 4 | struct Polynomial { 5 | // use llround(a[i].real()) when printing FFT output 6 | const double PI = acos(-1); 7 | static const int root = 565042129; 8 | static const int root_1 = 950391366; 9 | static const int root_pw = 1 << 20; 10 | static const int mod = 998244353; 11 | 12 | static int pow(ll a, int n) { 13 | int res = 1; 14 | for (a %= mod; n > 0; n >>= 1) { 15 | if (n & 1) 16 | res = (int)((1LL * res * a) % mod); 17 | a = (int)((a * 1ll * a) % mod); 18 | } 19 | return res; 20 | } 21 | int order; 22 | vector coeff; 23 | explicit Polynomial() : order(0), coeff(vector(0)) { 24 | } 25 | explicit Polynomial(vector coefficients) 26 | : order((int)coefficients.size()), coeff(coefficients) { 27 | } 28 | Polynomial(const Polynomial ©) 29 | : order(copy.order), coeff(vector(copy.coeff)) { 30 | } 31 | void resize(int nOrder) { 32 | int size = 1 << (ll)ceil(log2(nOrder)); 33 | coeff.resize(size, 0); 34 | } 35 | 36 | static void fft(vector> &coeff, bool invert = false) { 37 | int n = (int)coeff.size(); 38 | for (int i = 1, j = 0; i < n; i++) { 39 | int bit = n >> 1; 40 | for (; j & bit; bit >>= 1) 41 | j ^= bit; 42 | j ^= bit; 43 | if (i < j) 44 | swap(coeff[i], coeff[j]); 45 | } 46 | for (int len = 2; len <= n; len <<= 1) { 47 | double ang = 2 * PI / len * (invert ? -1 : 1); 48 | complex wlen(cos(ang), sin(ang)); 49 | for (int i = 0; i < n; i += len) { 50 | complex w(1); 51 | for (int j = 0; j < len / 2; j++) { 52 | complex u = coeff[i + j], 53 | v = coeff[i + j + len / 2] * w; 54 | coeff[i + j] = u + v; 55 | coeff[i + j + len / 2] = u - v; 56 | w *= wlen; 57 | } 58 | } 59 | } 60 | if (invert) { 61 | for (cd &x : coeff) 62 | x /= n; 63 | } 64 | } 65 | 66 | static void fft(vector &coeff, bool invert = false) { 67 | int n = (int)coeff.size(); 68 | for (int i = 1, j = 0; i < n; i++) { 69 | int bit = n >> 1; 70 | for (; j & bit; bit >>= 1) 71 | j ^= bit; 72 | j ^= bit; 73 | if (i < j) 74 | swap(coeff[i], coeff[j]); 75 | } 76 | for (int len = 2; len <= n; len <<= 1) { 77 | int wlen = invert ? root_1 : root; 78 | for (int i = len; i < root_pw; i <<= 1) 79 | wlen = (int)(1LL * wlen * wlen % mod); 80 | for (int i = 0; i < n; i += len) { 81 | int w = 1; 82 | for (int j = 0; j < len / 2; j++) { 83 | int u = coeff[i + j], 84 | v = (int)(1LL * coeff[i + j + len / 2] * w % mod); 85 | coeff[i + j] = u + v < mod ? u + v : u + v - mod; 86 | coeff[i + j + len / 2] = u - v >= 0 ? u - v : u - v + mod; 87 | w = (int)(1LL * w * wlen % mod); 88 | } 89 | } 90 | } 91 | if (invert) { 92 | int n_1 = pow(n, mod - 2); 93 | for (auto &x : coeff) 94 | x = (int)(1LL * x * n_1 % mod); 95 | } 96 | } 97 | 98 | friend Polynomial operator*(const Polynomial &a, 99 | const Polynomial &b) { 100 | decltype(a) x(a); 101 | decltype(b) y(b); 102 | int order = a.order + b.order; 103 | order = 1 << (ll)ceil(log2(order)); 104 | x.resize(order), y.resize(order); 105 | fft(x), fft(y); 106 | decltype(x.coeff) res(order); 107 | for (int i = 0; i < order; i++) 108 | res[i] = (x.coeff[i] * y.coeff[i]); 109 | fft(res, true); 110 | return Polynomial(x); 111 | } 112 | 113 | friend Polynomial operator^(const Polynomial &a, int power) { 114 | decltype(a) x(a); 115 | int order = a.order * power; 116 | x.resize(order); 117 | x.fft(); 118 | int size = (int)x.coeff.size(); 119 | decltype() poly(size); 120 | Polynomial res(poly); 121 | for (int i = 0; i < size; i++) 122 | poly[i] = pow(x.coeff[i], power); 123 | fft(res, true); 124 | res.order = order; 125 | return res; 126 | } 127 | }; 128 | 129 | // Code for finding closest match by Hamming distance of r in s |r| <= |s| 130 | // we reverse polynomial r and multiply with s 131 | // for (ll i = (int)r.size() - 1 - 1; i < s.size(); i++) 132 | // res[i] += z.coeff[i]; // z is the multiplication result 133 | // answers contained in res[sz(r) - 1] to res[sz(s) - 1] -------------------------------------------------------------------------------- /ref/FlowAlgorithms.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | #define AVG_CASE 4 | #ifdef AVG_CASE 5 | struct PushRelabel { 6 | struct Edge { 7 | ll from, to, cap, flow, index; 8 | Edge(ll dfrom, ll dto, ll dcap, ll dflow, ll dindex) 9 | : from(dfrom), to(dto), cap(dcap), flow(dflow), index(dindex) { 10 | } 11 | }; 12 | 13 | ll size; 14 | vector> graph; 15 | vector excess; 16 | vector dist, active, count; 17 | queue q; 18 | 19 | PushRelabel(ll n) 20 | : size(n), 21 | graph(size), 22 | excess(size), 23 | dist(size), 24 | active(size), 25 | count(2 * size) { 26 | } 27 | void add_edge(ll from, ll to, ll cap) { 28 | graph[from].push_back(Edge(from, to, cap, 0, graph[to].size())); 29 | if (from == to) 30 | graph[from].back().index++; 31 | graph[to].push_back(Edge(to, from, 0, 0, graph[from].size() - 1)); 32 | } 33 | void __enqueue(ll v) { 34 | if (!active[v] && excess[v] > 0) { 35 | active[v] = true; 36 | q.push(v); 37 | } 38 | } 39 | void __push(Edge &e) { 40 | ll amt = ll(min(excess[e.from], ll(e.cap - e.flow))); 41 | if (dist[e.from] <= dist[e.to] || amt == 0) 42 | return; 43 | e.flow += amt; 44 | graph[e.to][e.index].flow -= amt; 45 | excess[e.to] += amt; 46 | excess[e.from] -= amt; 47 | __enqueue(e.to); 48 | } 49 | void __gap(ll k) { 50 | for (ll v = 0; v < size; v++) { 51 | if (dist[v] < k) 52 | continue; 53 | count[dist[v]]--; 54 | dist[v] = max(dist[v], size + 1); 55 | count[dist[v]]++; 56 | __enqueue(v); 57 | } 58 | } 59 | void __relabel(ll v) { 60 | count[dist[v]]--; 61 | dist[v] = 2 * size; 62 | for (ll i = 0; i < (ll)graph[v].size(); i++) 63 | if (graph[v][i].cap - graph[v][i].flow > 0) 64 | dist[v] = min(dist[v], dist[graph[v][i].to] + 1); 65 | count[dist[v]]++; 66 | __enqueue(v); 67 | } 68 | void __discharge(ll v) { 69 | for (ll i = 0; excess[v] > 0 && i < (ll)graph[v].size(); i++) 70 | __push(graph[v][i]); 71 | if (excess[v] > 0) { 72 | if (count[dist[v]] == 1) 73 | __gap(dist[v]); 74 | else 75 | __relabel(v); 76 | } 77 | } 78 | ll max_flow(ll s, ll t) { 79 | count[0] = size - 1; 80 | count[size] = 1; 81 | dist[s] = size; 82 | active[s] = active[t] = true; 83 | for (ll i = 0; i < (ll)graph[s].size(); i++) { 84 | excess[s] += graph[s][i].cap; 85 | __push(graph[s][i]); 86 | } 87 | while (!q.empty()) { 88 | ll v = q.front(); 89 | q.pop(); 90 | active[v] = false; 91 | __discharge(v); 92 | } 93 | ll totflow = 0; 94 | for (ll i = 0; i < (ll)graph[s].size(); i++) 95 | totflow += graph[s][i].flow; 96 | return totflow; 97 | } 98 | }; 99 | #else 100 | struct Edge { 101 | int u, v; 102 | ll cap, flow; 103 | Edge() : u(0), v(0), cap(0), flow(0) { 104 | } 105 | Edge(int uu, int vv, ll ccap) : u(uu), v(vv), cap(ccap), flow(0) { 106 | } 107 | }; 108 | struct Dinic { 109 | int N; 110 | vector E; 111 | vector> g; 112 | vector d, pt; 113 | Dinic(int NN) : N(NN), E(0), g(N), d(N), pt(N) { 114 | } 115 | void addEdge(int u, int v, ll cap, ll rcap = 0) { 116 | if (u != v) { 117 | E.emplace_back(Edge(u, v, cap)); 118 | g[u].emplace_back(E.size() - 1); 119 | E.emplace_back(Edge(v, u, rcap)); 120 | g[v].emplace_back(E.size() - 1); 121 | } 122 | } 123 | bool BFS(int S, int T) { 124 | queue q({S}); 125 | fill(d.begin(), d.end(), N + 1); 126 | d[S] = 0; 127 | while (!q.empty()) { 128 | int u = q.front(); 129 | q.pop(); 130 | if (u == T) 131 | break; 132 | for (int k : g[u]) { 133 | Edge &e = E[k]; 134 | if (e.flow < e.cap && d[e.v] > d[e.u] + 1) { 135 | d[e.v] = d[e.u] + 1; 136 | q.emplace(e.v); 137 | } 138 | } 139 | } 140 | return d[T] != N + 1; 141 | } 142 | 143 | ll DFS(int u, int T, ll flow = -1) { 144 | if (u == T || flow == 0) 145 | return flow; 146 | for (int &i = pt[u]; i < (int)g[u].size(); ++i) { 147 | Edge &e = E[g[u][i]]; 148 | Edge &oe = E[g[u][i] ^ 1]; 149 | if (d[e.v] == d[e.u] + 1) { 150 | ll amt = e.cap - e.flow; 151 | if (flow != -1 && amt > flow) 152 | amt = flow; 153 | if (ll pushed = DFS(e.v, T, amt)) { 154 | e.flow += pushed; 155 | oe.flow -= pushed; 156 | return pushed; 157 | } 158 | } 159 | } 160 | return 0; 161 | } 162 | ll maxFlow(int S, int T) { 163 | ll total = 0; 164 | while (BFS(S, T)) { 165 | fill(pt.begin(), pt.end(), 0); 166 | while (ll flow = DFS(S, T)) 167 | total += flow; 168 | } 169 | return total; 170 | } 171 | }; 172 | #endif 173 | 174 | struct HopcroftKarp { 175 | static const int INF = 1e9; 176 | int size_u, size_v, nil; 177 | vector pair_u, pair_v, dist; 178 | vector> adjacency; 179 | 180 | bool __bfs() { 181 | queue q; 182 | for (int u = 0; u < size_u; u++) 183 | if (pair_u[u] == nil) 184 | dist[u] = 0, q.push(u); 185 | else 186 | dist[u] = INF; 187 | dist[nil] = INF; 188 | while (not q.empty()) { 189 | int u = q.front(); 190 | q.pop(); 191 | if (dist[u] >= dist[nil]) 192 | continue; 193 | for (int v : adjacency[u]) 194 | if (dist[pair_v[v]] == INF) 195 | dist[pair_v[v]] = dist[u] + 1, q.push(pair_v[v]); 196 | } 197 | return dist[nil] != INF; 198 | } 199 | bool __dfs(int u) { 200 | if (u == nil) 201 | return true; 202 | for (int v : adjacency[u]) 203 | if (dist[pair_v[v]] == dist[u] + 1) 204 | if (__dfs(pair_v[v])) { 205 | pair_v[v] = u, pair_u[u] = v; 206 | return true; 207 | } 208 | dist[u] = INF; 209 | return false; 210 | } 211 | 212 | public: 213 | HopcroftKarp(int u_size, int v_size) { 214 | nil = size_u = size_v = max(u_size, v_size); 215 | adjacency.resize(size_u + 1); 216 | dist.resize(size_u + 1); 217 | pair_u.resize(size_u + 1); 218 | pair_v.resize(size_v); 219 | } 220 | void add_edge(int u, int v) { 221 | adjacency[u].push_back(v); 222 | } 223 | int max_match() { 224 | fill(pair_u.begin(), pair_u.end(), nil); 225 | fill(pair_v.begin(), pair_v.end(), nil); 226 | int res = 0; 227 | while (__bfs()) 228 | for (int u = 0; u < size_u; u++) 229 | if (pair_u[u] == nil && __dfs(u)) 230 | res++; 231 | return res; 232 | } 233 | }; -------------------------------------------------------------------------------- /ref/Geometry.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | class Point { 4 | public: 5 | typedef long long coord_t; coord_t x, y; 6 | Point(coord_t coord_x = 0, coord_t coord_y = 0) { this->x = coord_x; this->y = coord_y; } 7 | Point(pair coord) { this->x = coord.first; this->y = coord.second; } 8 | friend bool operator<(const Point &a, const Point &b) { return (a.x != b.x) ? a.x < b.x : a.y < b.y; } 9 | friend bool operator==(const Point &a, const Point &b) { return (a.x == b.x) && (a.y == b.y); } 10 | friend istream &operator>>(istream &in, Point &p) { in >> p.x >> p.y; return in; } 11 | friend ostream &operator<<(ostream &out, Point &p) { out << p.x << " " << p.y; return out; } 12 | static coord_t area(const Point &a, const Point &b, const Point &c) { return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y); }; // Area function: area < 0 = clockwise, area > 0 counterclockwise 13 | static coord_t sq_dist(const Point &a, const Point &b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); } 14 | static coord_t cross(const Point &O, const Point &A, const Point &B) { return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x); } 15 | static coord_t dot(const Point &O, const Point &A, const Point &B) { return (A.x - O.x) * (B.x - O.x) + (A.y - O.y) * (B.y - O.y); } 16 | static coord_t area(const vector &polygon) { 17 | int n = polygon.size(); 18 | coord_t ans = 0; 19 | for (int i = 0; i < n; i++) 20 | ans += polygon[i].x * polygon[(i + 1) % n].y - polygon[i].y * polygon[(i + 1) % n].x; 21 | } 22 | static vector convex_hull(vector &a) { 23 | if (a.size() <= 3) return a; 24 | int n = a.size(), k = 0; sort(a.begin(), a.end()); 25 | vector result(2 * n); 26 | for (int i = 0; i < n; ++i) { 27 | while (k >= 2 && cross(result[k - 2], result[k - 1], a[i]) <= 0) k--; 28 | result[k++] = a[i]; 29 | } 30 | for (int i = n - 1, t = k + 1; i > 0; --i) { 31 | while (k >= t && cross(result[k - 2], result[k - 1], a[i - 1]) <= 0) k--; 32 | result[k++] = a[i - 1]; 33 | } 34 | result.resize(k - 1); return result; 35 | } 36 | }; -------------------------------------------------------------------------------- /ref/GraphAlgorithms.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | class Graph { 4 | public: 5 | enum NodeColor { VISITED, VISITING, UNVISITED }; 6 | struct Node { int index; vpl adjacent; NodeColor color = UNVISITED; }; 7 | vector list; int n; 8 | Graph(int n) { 9 | list.resize(n); 10 | for (int i = 0; i < n; i++) list[i].index = i; 11 | this->n = n; 12 | } 13 | void add_edge(int u, int v, long long w = 1) { 14 | list[u].adjacent.emplace_back(v, w); 15 | list[v].adjacent.emplace_back(u, w); 16 | } 17 | 18 | pair dijkstra(vll from) { 19 | vll dist(n, INT64_MAX), parent(n, INT32_MAX); 20 | priority_queue> q; 21 | for (auto index : from) dist[index] = 0, q.emplace(0, index); 22 | while (!q.empty()) { 23 | pll top = q.top(); q.pop(); 24 | if (top.first > dist[top.second]) continue; 25 | for (auto edge : list[top.second].adjacent) 26 | if (top.first + edge.second < dist[edge.first]) 27 | dist[edge.first] = top.first + edge.second, 28 | parent[edge.first] = top.second, 29 | q.emplace(top.first + edge.second, edge.first); 30 | } return {dist, parent}; 31 | } 32 | vector topological_sort() { 33 | vector in_degree(list.size(), 0), result; 34 | result.reserve(list.size()); 35 | for (auto node : list) for (auto route : node.adjacent) 36 | in_degree[route.first - 1]++; 37 | queue process; 38 | for (int i = 0; i < list.size(); i++) 39 | if (in_degree[i] == 0) { process.push(i); result.push_back(i); } 40 | while (!process.empty()) { 41 | int processing = process.front(); process.pop(); 42 | for (auto route : list[processing].adjacent) { 43 | in_degree[route.first - 1]--; 44 | if (in_degree[route.first - 1] == 0) { 45 | process.push(route.first - 1); 46 | result.push_back(route.first - 1); 47 | } 48 | } 49 | } 50 | return result; 51 | } 52 | mll components() { 53 | vbl visited(n); mll result(0); 54 | for (int i = 0; i < n; i++) { 55 | if (visited[i]) continue; 56 | vll component; stack process; 57 | process.push(list[i].index); component.push_back(i); visited[i] = true; 58 | while (!process.empty()) { 59 | ll processing = process.top(); process.pop(); 60 | for (pll neighbor : list[processing].adjacent) 61 | if (!visited[neighbor.first]) 62 | process.push(neighbor.first), component.push_back(neighbor.first), 63 | visited[neighbor.first] = true; 64 | } result.push_back(component); 65 | } return result; 66 | } 67 | pair bellman_ford(vll from) { 68 | vll distances(n, INT64_MAX); 69 | vll parent(n, INT32_MAX); 70 | for (ll &i : from) 71 | distances[i] = 0; 72 | for (int i = 0; i < n - 1; i++) 73 | for (int source = 0; source < n - 1; source++) { 74 | if (distances[source] == INT64_MAX) 75 | continue; 76 | for (const auto &edge : list[source].adjacent) { 77 | ll sink = edge.first; 78 | if (distances[source] + edge.second < distances[sink]) 79 | distances[sink] = distances[source] + edge.second, parent[sink] = source; 80 | } 81 | } 82 | for (ll source = 0; source < n - 1; source++) // -ve cycle check 83 | for (const auto &edge : list[source].adjacent) { 84 | ll sink = edge.first; 85 | if (distances[source] + edge.second < distances[sink]) { 86 | for (ll i : from) distances[i] = -1; 87 | return {distances, parent}; 88 | } 89 | } 90 | return {distances, parent}; 91 | } 92 | mll floyd_warshall() { 93 | mll distances(n, vll(n, INT64_MAX)); 94 | for (int i = 0; i < n; i++) distances[i][i] = 0; 95 | for (int i = 0; i < n; i++) for (auto route : list[i].adjacent) 96 | distances[i][route.first] = route.second; 97 | for (int k = 0; k < n; k++) { 98 | for (int i = 0; i < n; i++) { 99 | for (int j = 0; j < n; j++) { 100 | if (distances[i][k] == INT64_MAX || distances[k][j] == INT64_MAX) continue; 101 | distances[i][j] = min(distances[i][j], distances[i][k] + distances[k][j]); 102 | } 103 | } 104 | } return distances; 105 | } 106 | pair prims_mst() { 107 | priority_queue> routes; 108 | vll costs(n); 109 | vbl visited(n, false); 110 | for (int i = 0; i < n; i++) { 111 | if (!visited[i]) routes.emplace(INT32_MAX, i); 112 | while (!routes.empty()) { 113 | pll best = routes.top(); routes.pop(); 114 | if (!visited[best.second]) costs[best.second] = best.first; 115 | visited[best.second] = false; 116 | for (const auto &path : list[best.second].adjacent) 117 | if (!visited[path.second]) routes.push(path); 118 | } 119 | } 120 | return {accumulate(costs.begin(), costs.end(), 0), costs}; 121 | } 122 | }; -------------------------------------------------------------------------------- /ref/MathematicsTheory.tex: -------------------------------------------------------------------------------- 1 | \subsection{Mobius Inversions} 2 | 3 | \begin{itemize} 4 | 5 | \item $\phi \circ I = \text{id}$ i.e. $\sum_{d|n} \phi(d)=n$. Hence, $\phi = \mu \circ \text{id}$ i.e. $\phi(d)=\sum_{d|n} \mu(d) \frac{n}{d}$ 6 | \item Count of numbers coprime to $n$ and lesser than $n = phi(n)$ \\ 7 | Sum of numbers coprime to $n$ and lesser than $n$ is $\frac{n}{2}\phi(n)$ \\ 8 | Proved using the fact that if $x$ is coprime to $n$ then so is $n-x$ coprime to $n$. Sum over both and take average 9 | \item $\sum_{d|n} \mu(d)f(d)=\prod_{p|n} (1 - f(p))$ ($p$ are its prime factors) 10 | \item $\sum_{d|n} \mu^2(d)f(d)=\prod_{p|n} (1 + f(p))$ 11 | \item $\phi(mn) = \frac{\phi(m)\phi(n)\gcd(m,n)}{\phi(\gcd(m,n))}$ 12 | \item $\phi(p^a) = p^{a-1}\phi{(p)}$ 13 | \end{itemize} 14 | 15 | \subsection{Chinese Remainder Theorem} 16 | 17 | System $x \equiv a_i(\mod m_i)$ for $i = 1, \ldots, n$, with pairwise relatively prime $m_i$ has a unique solution modulo $M = \prod m_i$ 18 | $x=\sum_{i} a_ib_i\frac M{m_i} (\mod M)$ where $b_i$ is modular inverse of $\frac M{m_i}$ modulo $m_i$. 19 | 20 | System $x \equiv a (\mod m)$, $x \equiv b (\mod n)$ has solutions iff $a \equiv b (\mod g)$, where $g = \gcd(m, n)$. The 21 | solution is unique modulo $L = \frac{mn}{g}$, and equals: $x \equiv a + T (b − a)m/g \equiv b + S(a − b)n/g (\mod L)$, 22 | where $S$ and $T$ are integer solutions of $mT + nS = \gcd(m, n)$. 23 | 24 | Euler's theorem: $a^{\phi(n)}\equiv 1(\mod n)$, if $\gcd(a,n)=1$ 25 | Wilson's theorem: $p$ is prime iff $(p-1)! \equiv -1(\mod p)$ 26 | Primitive Pythagorean triple generator: $(m^2-n^2)^2 + (2mn)^2 = (m^2+n^2)^2$ 27 | Postage stamps/McNuggets problem: Let $a$, $b$ be coprime integers. There are exactly $\frac 12(a−1)(b−1)$ numbers not of form $ax+by (x, y \geq 0)$, and the largest is $(a−1)(b−1)−1 = ab−a−b$. 28 | 29 | Fermat’s two-squares theorem: Odd prime $p$ can be represented as a sum of two squares iff 30 | $p \equiv 1 (\mod 4)$. A product of two sums of two squares is a sum of two squares. Thus, $n$ is a sum of 31 | two squares iff every prime of form $p = 4k + 3$ occurs an even number of times in $n$’s factorization. 32 | 33 | Counting Primes Fast: To count number of primes lesser than big $n$. Use following recurrence. 34 | $\text{dp}[n][j] =\text{dp}[n][j + 1] + \text{dp}[n/p_j][j]$ where $dp[i][j]$ stores count of numbers lesser than equal to $i$ 35 | having all prime divisors greater than equal to $p_j$ . Precompute this for all $i$ less than some small $k$ 36 | and for others use the recurrence to compute in small time. 37 | 38 | Compute $P_N(x)$ in $T(n)=T(n/2)+\mathcal{O}(n\log n)\approx \mathcal{O}(n\log n)$ $P_{2N}(x) = P_{N}(x)P_{N}(x+N)$. using polynomial shifting. Say, $P_N(x) = \prod \limits_{i=1}^N (x+i) = \sum_{i=0}^N c_i.x^i$. 39 | Then, $P_N(x+N) = \sum_{i=0}^N h_i.x^i$, where, $h_i = \frac{1}{i!} . (\text{coefficient of } x^{N-i} in A(x)B(x))$ where, $A(x) = \sum \limits_{i=0}^{N} (c_{N-i}.(N-i)!) . x^i$, and $B(x) = \sum \limits_{i=0}^{N} \left( \frac {N^i}{i!} \right) . x^i$ 40 | 41 | \begin{verbatim} 42 | MUL(N) // computes (x+1)(x+2)...(x+N) in O(NlogN) 43 | if N==1: 44 | return (x+1) 45 | C = MUL(N/2) 46 | H = convolute(A,B) // use C to obtain A 47 | ANS = convolute(C,H) 48 | if N is odd: 49 | ANS *= (x+N) // naive multiplication will do - O(N) 50 | return ANS 51 | \end{verbatim} 52 | 53 | Computing $10^{18}$-th Fib number fast: use $f(2k) = f(k)^2 + f(k - 1)^2, f(2k + 1) = f(k)f(k + 1) + f(k - 1)f(k)$. This has at most $\mathcal{O}(\log n\log\log n)$ states. -------------------------------------------------------------------------------- /ref/MatrixTools.cpp: -------------------------------------------------------------------------------- 1 | // solving systems of linear equations(AX = B) 2 | // (2) inverting matrices(AX = I) 3 | // (3) computing determinants of square matrices 4 | // O(nˆ3) 5 | // INPUT : a[][] = an nxn matrix; b[][] = an nxm matrix 6 | // OUTPUT: 7 | // X = an nxm matrix(stored in b[][]) 8 | // Aˆ{-1} = an nxn matrix(stored in a[][]) 9 | // returns determinant of a[][] 10 | 11 | const double EPS = 1e-10; 12 | // T is data type of matrix elements 13 | T GaussJordan(VVT &a, VVT &b) { 14 | const int n = a.size(); 15 | const int m = b[0].size(); 16 | VI irow(n), icol(n), ipiv(n); 17 | T det = 1; 18 | for (int i = 0; i < n; i++) { 19 | int pj = -1, pk = -1; 20 | for (int j = 0; j < n; j++) 21 | if (!ipiv[j]) 22 | for (int k = 0; k < n; k++) 23 | if (!ipiv[k]) 24 | if (pj == -1 || fabs(a[j][k]) > fabs(a[pj][pk])) { 25 | pj = j; 26 | pk = k; 27 | } 28 | if (fabs(a[pj][pk]) < EPS) { 29 | cerr << "Matrix is singular." << endl; 30 | exit(0); 31 | } 32 | ipiv[pk]++; 33 | swap(a[pj], a[pk]); 34 | 35 | swap(b[pj], b[pk]); 36 | if (pj != pk) 37 | det *= -1; 38 | irow[i] = pj; 39 | icol[i] = pk; 40 | T c = 1.0 / a[pk][pk]; 41 | det *= a[pk][pk]; 42 | a[pk][pk] = 1.0; 43 | for (int p = 0; p < n; p++) 44 | a[pk][p] *= c; 45 | for (int p = 0; p < m; p++) 46 | b[pk][p] *= c; 47 | for (int p = 0; p < n; p++) 48 | if (p != pk) { 49 | c = a[p][pk]; 50 | a[p][pk] = 0; 51 | for (int q = 0; q < n; q++) 52 | a[p][q] -= a[pk][q] * c; 53 | for (int q = 0; q < m; q++) 54 | b[p][q] -= b[pk][q] * c; 55 | } 56 | } 57 | for (int p = n - 1; p >= 0; p--) 58 | if (irow[p] != icol[p]) { 59 | for (int k = 0; k < n; k++) 60 | swap(a[k][irow[p]], a[k][icol[p]]); 61 | } 62 | return det; 63 | }// gets the rank of a matrix. 64 | // Running time: O(nˆ3) 65 | // INPUT: a[][] = an nxm matrix 66 | // OUTPUT: rref[][] = an nxm matrix (stored in a[][]) 67 | // returns rank of a[][] 68 | 69 | int rref(VV &a) { 70 | int n = a.size(), m = a[0].size(), r = 0; 71 | 72 | for (int c = 0; c < m && r < n; c++) { 73 | int j = r; 74 | for (int i = r + 1; i < n; i++) 75 | if (fabs(a[i][c]) > fabs(a[j][c])) 76 | j = i; 77 | 78 | if (fabs(a[j][c]) < EPS) 79 | continue; 80 | swap(a[j], a[r]); 81 | 82 | T s = 1.0 / a[r][c]; 83 | 84 | for (int j = 0; j < m; j++) 85 | a[r][j] *= s; 86 | 87 | for (int i = 0; i < n; i++) { 88 | if (i != r) { 89 | T t = a[i][c]; 90 | for (int j = 0; j < m; j++) { 91 | a[i][j] -= t * a[r][j]; 92 | } 93 | } 94 | } 95 | 96 | r++; 97 | } 98 | 99 | return r; 100 | }// Solves LP with constraints cˆT x, Ax <= b, x >= 0 101 | // A: m x n matrix 102 | // b: m-dimensional vector 103 | // c: n-dimensional vector 104 | // x: a vector where the optimal solution will be stored 105 | // OUTPUT: value of the optimal solution (infinity if unbounded 106 | // above, nan if infeasible) 107 | // To use this code, create an LPSolver object with A, b, and c as 108 | // arguments. Then, call Solve(x) 109 | 110 | struct LPSolver { 111 | int m, n; 112 | VI B, N; 113 | VVD D; 114 | LPSolver(const VVD &A, const VD &b, const VD &c) 115 | : m(b.size()), n(c.size()), N(n + 1), B(m), D(m + 2, VD(n + 2)) { 116 | for (int i = 0; i < m; i++) 117 | for (int j = 0; j < n; j++) 118 | D[i][j] = A[i][j]; 119 | for (int i = 0; i < m; i++) { 120 | B[i] = n + i; 121 | D[i][n] = -1; 122 | D[i][n + 1] = b[i]; 123 | } 124 | for (int j = 0; j < n; j++) { 125 | N[j] = j; 126 | D[m][j] = -c[j]; 127 | } 128 | N[n] = -1; 129 | D[m + 1][n] = 1; 130 | } 131 | void Pivot(int r, int s) { 132 | double inv = 1.0 / D[r][s]; 133 | for (int i = 0; i < m + 2; i++) 134 | if (i != r) 135 | for (int j = 0; j < n + 2; j++) 136 | if (j != s) 137 | D[i][j] -= D[r][j] * D[i][s] * inv; 138 | for (int j = 0; j < n + 2; j++) 139 | if (j != s) 140 | D[r][j] *= inv; 141 | for (int i = 0; i < m + 2; i++) 142 | if (i != r) 143 | D[i][s] *= -inv; 144 | D[r][s] = inv; 145 | swap(B[r], N[s]); 146 | } 147 | bool Simplex(int phase) { 148 | int x = phase == 1 ? m + 1 : m; 149 | while (true) { 150 | int s = -1; 151 | for (int j = 0; j <= n; j++) { 152 | if (phase == 2 && N[j] == -1) 153 | continue; 154 | if (s == -1 || D[x][j] < D[x][s] || 155 | D[x][j] == D[x][s] && N[j] < N[s]) 156 | s = j; 157 | } 158 | if (D[x][s] > -EPS) 159 | return true; 160 | int r = -1; 161 | for (int i = 0; i < m; i++) { 162 | if (D[i][s] < EPS) 163 | continue; 164 | if (r == -1 || D[i][n + 1] / D[i][s] < D[r][n + 1] / D[r][s] || 165 | (D[i][n + 1] / D[i][s]) == (D[r][n + 1] / D[r][s]) && 166 | B[i] < B[r]) 167 | r = i; 168 | } 169 | if (r == -1) 170 | return false; 171 | Pivot(r, s); 172 | } 173 | } 174 | DOUBLE Solve(VD &x) { 175 | int r = 0; 176 | for (int i = 1; i < m; i++) 177 | if (D[i][n + 1] < D[r][n + 1]) 178 | r = i; 179 | if (D[r][n + 1] < -EPS) { 180 | Pivot(r, n); 181 | if (!Simplex(1) || D[m + 1][n + 1] < -EPS) 182 | return -numeric_limits::infinity(); 183 | for (int i = 0; i < m; i++) 184 | if (B[i] == -1) { 185 | int s = -1; 186 | for (int j = 0; j <= n; j++) 187 | if (s == -1 || D[i][j] < D[i][s] || 188 | D[i][j] == D[i][s] && N[j] < N[s]) 189 | s = j; 190 | Pivot(i, s); 191 | } 192 | } 193 | if (!Simplex(2)) 194 | return numeric_limits::infinity(); 195 | x = VD(n); 196 | for (int i = 0; i < m; i++) 197 | if (B[i] < n) 198 | x[B[i]] = D[i][n + 1]; 199 | return D[m][n + 1]; 200 | } 201 | }; -------------------------------------------------------------------------------- /ref/MergeSortTree.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | template 4 | struct MergeSortTree { 5 | int size; 6 | vector data; 7 | vector> tree_idx; 8 | vector> tree_val; 9 | long long inversions; 10 | 11 | template 12 | vector merge(const vector &arr1, 13 | const vector &arr2) { 14 | int n = arr1.size(), m = arr2.size(); 15 | vector result; 16 | result.reserve(n + m); 17 | for (int x = 0, y = 0; x < n || y < m;) { 18 | if (x < n && (y >= m || arr1[x] <= arr2[y])) 19 | result.push_back(arr1[x++]); 20 | else 21 | result.push_back(arr2[y++]), inversions += n - x; 22 | } 23 | return move(result); 24 | } 25 | int order_fn(const Type &value, const vector &arr) { 26 | return lower_bound(arr.begin(), arr.end(), value) - arr.begin(); 27 | } 28 | explicit MergeSortTree(const vector &list) { 29 | for (size = 1; size < list.size(); size *= 2) 30 | ; 31 | // Make a tree based on the values 32 | tree_val.resize(2 * size); 33 | data = vector(list); 34 | for (int i = 0; i < list.size(); i++) 35 | tree_val[i + size].push_back(i); 36 | for (int i = size - 1; i > 0; --i) 37 | tree_val[i] = merge(tree_val[i << 1], tree_val[i << 1 | 1]); 38 | // Make a tree based on the indices 39 | tree_idx.resize(2 * size); 40 | vector> convert(list.size()); 41 | for (int i = 0; i < list.size(); i++) 42 | convert[i].first = list[i], convert[i].second = i; 43 | sort(convert.begin(), convert.end()); 44 | for (int i = 0; i < list.size(); i++) 45 | tree_idx[i + size].push_back(convert[i].second); 46 | for (int i = size - 1; i > 0; --i) 47 | tree_idx[i] = merge(tree_idx[i << 1], tree_idx[i << 1 | 1]); 48 | } 49 | int order_of_key(int l, int r, Type value) { 50 | int result = 0; 51 | for (l = l + size, r = r + size; l < r; l >>= 1, r >>= 1) { 52 | if (l & 1) 53 | result += order_fn(value, tree_val[l++]); 54 | if (r & 1) 55 | result += order_fn(value, tree_val[--r]); 56 | } 57 | return result; 58 | } 59 | int key_of_order(int l, int r, int order, int node = 0, int x = 0, 60 | int y = -1) { 61 | if (y == -1) 62 | y = size; 63 | if (x + 1 == y) 64 | return tree_idx[node][0]; 65 | int m = (upper_bound(tree_idx[2 * node].begin(), 66 | tree_idx[2 * node].end(), r - 1) - 67 | tree_idx[2 * node].begin()) - 68 | (lower_bound(tree_idx[2 * node].begin(), 69 | tree_idx[2 * node].end(), l) - 70 | tree_idx[2 * node].begin()); 71 | if (m >= order) 72 | return key_of_order(l, r, order, node << 1, x, (x + y) / 2); 73 | else 74 | return key_of_order(l, r, order - m, node << 1 | 1, (x + y) / 2, y); 75 | } 76 | }; -------------------------------------------------------------------------------- /ref/Miscelleneous.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | alias gww='g++ -Wall -pedantic -pedantic-errors -Wextra -Wcast-align -Wcast-qual -Wconversion -Wfloat-equal -Wformat=2 -Wformat-nonliteral -Winit-self -Winline -Winvalid-pch -Wmissing-field-initializers -Wmissing-noreturn -Wpointer-arith -Wredundant-decls -Wstack-protector -Wstrict-aliasing=2 -Wswitch-default -Wunreachable-code -Wunused -Wunused-but-set-variable -Wunused-parameter' 4 | alias gmm="gww -fsanitize=address -fsanitize=undefined -D_GLIBCXX_DEBUG" 5 | 6 | #pragma GCC optimize("Ofast") 7 | #pragma GCC optimize ("unroll-loops") 8 | #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") 9 | 10 | ll gcd(ll a, ll b, ll &x, ll &y) {int g = a;x = 1, y = 0;if (b != 0)g = gcd(b, a % b, y, x), y -= a / b * x;return g;} 11 | ll mod_inverse(ll a, ll mod) {ll x, y;gcd(a, mod, x, y);return (x + mod) % mod;} 12 | // find z: z % m1 = r1, z % m2 = r2. Here, z is unique modulo M = lcm(m1, m2). 13 | // Return (z, M). On failure, M = -1. 14 | pll CRT(int m1, int r1, int m2, int r2) {int s, t;int g = extended_euclid(m1, m2, s, t); 15 | // m1s+m2t=g 16 | if (r1 % g != r2 % g)return {0, -1};return {mod(s * r2 * m1 + t * r1 * m2, m1 * m2) / g, m1 * m2 / g};} 17 | 18 | #include 19 | #include 20 | using namespace __gnu_pbds; 21 | typedef tree, rb_tree_tag, 22 | tree_order_statistics_node_update> 23 | ordered_set; 24 | 25 | // deterministic for all n <=2 ^ 64 26 | bool MRPrime(ll N) {int primes[12] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};if (N <= 1)return false;for (auto p : primes) {if (p == N)return true;if (N % p == 0)return false;}ll c = N - 1, g = 0;while (!(c & 1))c >>= 1, ++g;for (auto p : primes) {ll k = mod_power(p, c, N);for (int j = 0; j < g; ++j) {ll kk = mod_multiply(k, k, N);if (kk == 1 && k != 1 && k != N - 1)return false;k = kk;}if (k != 1)return false;}return true;} -------------------------------------------------------------------------------- /ref/MobiusSieve.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | class Multiplicative { 4 | // This is the definition for PHI 5 | #define fn_prime_values(prime) (prime - 1) 6 | #define fn_non_coprime(num, prime) (fn[num] * prime) 7 | public: 8 | ll size; vll fn, primes, lowest_prime_factor; 9 | Multiplicative(ll size) { 10 | size = size; 11 | lowest_prime_factor = vector(size, 0); 12 | fn = vector(size, 0); 13 | // https://stackoverflow.com/questions/34260399 - linear sieve 14 | for (ll i = 2; i < size; i++) 15 | lowest_prime_factor[i] = i; 16 | // put any specific initialization code here like - multiplicative_fn[1] = 1; 17 | for (ll i = 2; i < size; i++) { 18 | if (lowest_prime_factor[i] == i) { fn[i] = fn_prime_values(i); primes.push_back(i); } 19 | for (auto p : primes) { 20 | ll ith_multiple = i * p; 21 | if (ith_multiple >= size) break; 22 | lowest_prime_factor[ith_multiple] = min(lowest_prime_factor[i], p); 23 | if (i % p) { fn[ith_multiple] = fn[i] * fn[p]; } 24 | else { fn[ith_multiple] = fn_non_coprime(i, p); break; } 25 | } 26 | } 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /ref/PalindromicTree.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | struct PalindromicTree { 4 | const static long long MAXN = 100000; 5 | struct Node { 6 | int start, end; 7 | int length; 8 | int insert_edge[26]; 9 | int suffix_edge; 10 | }; 11 | Node root1, root2; 12 | Node tree[MAXN]; 13 | int curr_node, ptr, size; 14 | string s; 15 | 16 | void insert(int idx) { 17 | int tmp = curr_node; 18 | while (true) { 19 | int curLength = tree[tmp].length; 20 | if (idx - curLength >= 1 and s[idx] == s[idx - curLength - 1]) 21 | break; 22 | tmp = tree[tmp].suffix_edge; 23 | } 24 | if (tree[tmp].insert_edge[s[idx] - 'a'] != 0) { 25 | curr_node = tree[tmp].insert_edge[s[idx] - 'a']; 26 | return; 27 | } 28 | ptr++; 29 | tree[tmp].insert_edge[s[idx] - 'a'] = ptr; 30 | tree[ptr].length = tree[tmp].length + 2; 31 | tree[ptr].end = idx; 32 | tree[ptr].start = idx - tree[ptr].length + 1; 33 | tmp = tree[tmp].suffix_edge; 34 | curr_node = ptr; 35 | if (tree[curr_node].length == 1) { 36 | tree[curr_node].suffix_edge = 2; 37 | return; 38 | } 39 | while (true) { 40 | int cur_length = tree[tmp].length; 41 | if (idx - cur_length >= 1 and s[idx] == s[idx - cur_length - 1]) 42 | break; 43 | tmp = tree[tmp].suffix_edge; 44 | } 45 | tree[curr_node].suffix_edge = tree[tmp].insert_edge[s[idx] - 'a']; 46 | } 47 | PalindromicTree(string st) { 48 | root1.length = -1, root1.suffix_edge = 1, root2.length = 0, 49 | root2.suffix_edge = 1, tree[1] = root1, tree[2] = root2, ptr = 2; 50 | curr_node = 1, s = st, size = st.size(); 51 | for (int i = 0; i < size; i++) 52 | insert(i); 53 | } 54 | vpl get_palindromes() { 55 | vpl res(ptr - 2); 56 | for (int i = 3; i <= ptr; i++) 57 | res[i - 2] = {tree[i].start, tree[i].end}; 58 | return res; 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /ref/SegmentTree.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | template 4 | struct LazySegtree { 5 | int size; 6 | vector tree, lazy; 7 | Type _default; 8 | function _operation; 9 | function _setter; 10 | 11 | void split(int node) { 12 | lazy[2 * node] = _setter(lazy[2 * node], lazy[node]); 13 | tree[2 * node] = _setter(tree[2 * node], lazy[node]); 14 | lazy[2 * node + 1] = _setter(lazy[2 * node + 1], lazy[node]); 15 | tree[2 * node + 1] = _setter(tree[2 * node + 1], lazy[node]); 16 | lazy[node] = _default; 17 | } 18 | void merge(int node) { tree[node] = _operation(tree[2 * node], tree[2 * node + 1]); } 19 | 20 | LazySegtree(int n, const function &op, 21 | const function &set, const Type identity) { 22 | for (size = 1; size < n; size <<= 1); 23 | _setter = set, _operation = op, _default = identity; 24 | tree.assign(2 * size, _default); 25 | lazy.assign(2 * size, _default); 26 | } 27 | 28 | void modify(int l, int r, Type delta, int node = 1, int x = 0, int y = -1) { 29 | if (y == -1) y = size; 30 | if (r <= x || l >= y) return; 31 | if (l <= x && y <= r) { 32 | lazy[node] = _setter(lazy[node], delta); 33 | tree[node] = _setter(tree[node], delta); 34 | return; 35 | } 36 | split(node); modify(l, r, delta, 2 * node, x, (x + y) / 2); 37 | modify(l, r, delta, 2 * node + 1, (x + y) / 2, y); merge(node); 38 | } 39 | Type query(int l, int r, int node = 1, int x = 0, int y = -1) { 40 | if (y == -1) y = size; 41 | if (r <= x || l >= y) return _default; 42 | if (l <= x && y <= r) return tree[node]; 43 | split(node); Type lres = query(l, r, 2 * node, x, (x + y) / 2); 44 | Type rres = query(l, r, 2 * node + 1, (x + y) / 2, y); merge(node); 45 | return _operation(lres, rres); 46 | } 47 | }; 48 | 49 | template 50 | struct ImplicitSegupdate { 51 | struct Node { 52 | Type data = 0; 53 | Node *l_ptr = nullptr, *r_ptr = nullptr; 54 | Node *l_child() { if (l_ptr == nullptr) l_ptr = new Node, r_ptr = new Node; return l_ptr; } 55 | Node *r_child() { if (r_ptr == nullptr) l_ptr = new Node, r_ptr = new Node; return r_ptr; } 56 | }; 57 | int size; Node *root; function _setter; 58 | ImplicitSegupdate(int n, const function &set) { 59 | for (size = 1; size < n; size <<= 1) ; 60 | _setter = set; root = new Node; 61 | } 62 | void modify(int l, int r, Type delta, Node *node = nullptr, int x = 0, 63 | int y = -1) { 64 | if (node == nullptr) node = root, y = size; 65 | if (r <= x || l >= y) return; 66 | if (l <= x && y <= r) { node->data = _setter(node->data, delta); return; } 67 | modify(l, r, delta, node->l_child(), x, (x + y) / 2); 68 | modify(l, r, delta, node->r_child(), (x + y) / 2, y); 69 | } 70 | Type query(int p, Node *node = nullptr, int x = 0, int y = -1) { 71 | if (node == nullptr) node = root, y = size; 72 | if (x == p && y == p + 1) return node->data; 73 | if (x <= p && p < (x + y) / 2) return _setter(node->data, query(p, node->l_child(), x, (x + y) / 2)); 74 | else return _setter(node->data, query(p, node->r_child(), (x + y) / 2, y)); 75 | } 76 | }; 77 | 78 | struct PersistentSegtree { 79 | struct Node { 80 | int l, r, val; 81 | Node() { l = r = val = 0; } 82 | }; 83 | int node_size, query_size; int curr; 84 | vector root; vector seg; 85 | 86 | PersistentSegtree(int n, int q) { 87 | node_size = n, query_size = q; 88 | seg.resize(2 * (n + q * (log2(n) + 1))); 89 | root = vector(query_size + 10); 90 | curr = 1, seg[curr].l = seg[curr].r = seg[curr].val = 0; 91 | } 92 | int _new_node(int val, int l, int r) { 93 | seg[curr].val = val, seg[curr].l = l, seg[curr].r = r; 94 | return curr++; 95 | } 96 | int insert(int cur, int idx, int val, int lo, int hi) { 97 | if (idx < lo || idx > hi) 98 | return cur; 99 | else if (lo == hi) 100 | return _new_node(val, 0, 0); 101 | int mid = (lo + hi) >> 1; 102 | int pos = _new_node(-1, insert(seg[cur].l, idx, val, lo, mid), 103 | insert(seg[cur].r, idx, val, mid + 1, hi)); 104 | seg[pos].val = max(seg[seg[pos].l].val, seg[seg[pos].r].val); 105 | return pos; 106 | } 107 | }; -------------------------------------------------------------------------------- /ref/StonglyConnected.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | struct DirectedGraph { 4 | int size, curr; 5 | vector> adjacent_f, adjacent_r, comp_nodes; 6 | vector order, comp; 7 | vector visited; 8 | 9 | DirectedGraph(int n) { 10 | size = n; 11 | order.resize(size); 12 | adjacent_f.resize(size); 13 | } 14 | void add_edge(int v1, int v2) { 15 | adjacent_f[v1].push_back(v2); 16 | adjacent_r[v2].push_back(v1); 17 | } 18 | void _scc_dfs1(int u) { 19 | visited[u] = 1; 20 | for (auto w : adjacent_f[u]) 21 | if (!visited[w]) 22 | _scc_dfs1(w); 23 | order.push_back(u); 24 | } 25 | void _scc_dfs2(int u) { 26 | visited[u] = 1; 27 | comp[u] = curr; 28 | comp_nodes[curr].push_back(u); 29 | for (auto w : adjacent_r[u]) 30 | if (!visited[w]) 31 | _scc_dfs2(w); 32 | } 33 | void stongly_connected_components() { 34 | fill(visited.begin(), visited.end(), false); 35 | order.clear(); 36 | for (int i = 0; i < size; i++) 37 | if (!visited[i]) 38 | _scc_dfs1(i); 39 | fill(visited.begin(), visited.end(), false); 40 | reverse(order.begin(), order.end()); 41 | curr = 0; 42 | for (auto u : order) 43 | if (!visited[u]) 44 | comp_nodes[++curr].clear(), _scc_dfs2(u); 45 | } 46 | }; 47 | 48 | struct Satisfiability : DirectedGraph { 49 | vector val; 50 | Satisfiability(int size) : DirectedGraph(2 * size) { 51 | val = vector(size, false); 52 | } 53 | 54 | bool solvable(int vars) { 55 | stongly_connected_components(); 56 | for (int i = 0; i < vars; i++) 57 | if (comp[var(i)] == comp[NOT(var(i))]) 58 | return false; 59 | return true; 60 | } 61 | vector solve() { 62 | fill(val.begin(), val.end(), 0); 63 | for (int i = 1; i <= curr; i++) 64 | for (auto it : comp_nodes[i]) { 65 | int u = it >> 1; 66 | if (val[u]) 67 | continue; 68 | val[u] = (it & 1 ? +1 : -1); 69 | } 70 | return val; 71 | } 72 | int var(int x) { 73 | return x << 1; 74 | } 75 | int NOT(int x) { 76 | return x ^ 1; 77 | } 78 | void add_imp(int v1, int v2) { 79 | add_edge(v1, v2); 80 | add_edge(1 ^ v2, 1 ^ v1); 81 | } 82 | void add_equiv(int v1, int v2) { 83 | add_imp(v1, v2); 84 | add_imp(v2, v1); 85 | } 86 | void add_or(int v1, int v2) { 87 | add_edge(1 ^ v1, v2); 88 | add_edge(1 ^ v2, v1); 89 | } 90 | void add_xor(int v1, int v2) { 91 | add_or(v1, v2); 92 | add_or(1 ^ v1, 1 ^ v2); 93 | } 94 | void add_true(int v1) { 95 | add_edge(1 ^ v1, v1); 96 | } 97 | void add_and(int v1, int v2) { 98 | add_true(v1); 99 | add_true(v2); 100 | } 101 | }; -------------------------------------------------------------------------------- /ref/TreapsIntervals.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | struct Treap { 4 | struct Node { 5 | int val, prior, size; 6 | Node *l, *r; 7 | }; 8 | Node* root; 9 | 10 | int size(Node* node) { 11 | return node ? node->size : 0; 12 | } 13 | 14 | void split(Node* t, Node*& l, Node*& r, int key) { 15 | if (!t) 16 | l = r = NULL; 17 | else if (t->val <= key) 18 | split(t->r, t->r, r, key), l = t; 19 | else 20 | split(t->l, l, t->l, key), r = t; 21 | if (t) 22 | t->size = size(t->l) + 1 + size(t->r); 23 | } 24 | void merge(Node*& t, Node* l, Node* r) { 25 | if (!l || !r) 26 | t = l ? l : r; 27 | else if (l->prior > r->prior) 28 | merge(l->r, l->r, r), t = l; 29 | else 30 | merge(r->l, l, r->l), t = r; 31 | if (t) 32 | t->size = size(t->l) + 1 + size(t->r); 33 | } 34 | void insert(Node*& root, Node* it) { 35 | if (!root) 36 | root = it; 37 | else if (it->prior > root->prior) 38 | split(root, it->l, it->r, it->val), root = it; 39 | else 40 | insert(root->val < it->val ? root->r : root->l, it); 41 | if (root) 42 | root->size = size(root->l) + 1 + size(root->r); 43 | } 44 | void erase(Node*& root, int key) { 45 | if (!root) 46 | return; 47 | else if (root->val == key) { 48 | Node* x = root; 49 | merge(root, root->l, root->r); 50 | free(x); 51 | } else 52 | erase(root->val < key ? root->r : root->l, key); 53 | if (root) 54 | root->size = size(root->l) + 1 + size(root->r); 55 | } 56 | void unite(Node*& root, Node* l, Node* r) { 57 | if (!l || !r) 58 | return void(root = l ? l : r); 59 | Node *lt, *rt; 60 | if (l->prior < r->prior) 61 | swap(l, r); 62 | split(r, lt, rt, l->val); 63 | unite(l->l, l->l, lt); 64 | unite(l->r, l->r, rt); 65 | root = l; 66 | if (root) 67 | root->size = size(root->l) + 1 + size(root->r); 68 | } 69 | Node* _create_node(int val) { 70 | Node* ret = (Node*)malloc(sizeof(Node)); 71 | ret->val = val; 72 | ret->size = 1; 73 | ret->prior = rand(); 74 | ret->l = ret->r = NULL; 75 | return ret; 76 | } 77 | // insert(_create_node(x), head); 78 | }; 79 | 80 | struct IntervalTreap : Treap { 81 | struct Node { 82 | int prior, size, val, sum, lazy; 83 | Node *l, *r; 84 | }; 85 | int sz(Node* t) { 86 | return t ? t->size : 0; 87 | } 88 | void upd_sz(Node* t) { 89 | if (t) 90 | t->size = sz(t->l) + 1 + sz(t->r); 91 | } 92 | void lazy(Node* t) { 93 | if (!t || !t->lazy) 94 | return; 95 | t->val += t->lazy; 96 | t->sum += t->lazy * sz(t); 97 | if (t->l) 98 | t->l->lazy += t->lazy; 99 | if (t->r) 100 | t->r->lazy += t->lazy; 101 | t->lazy = 0; 102 | } 103 | void reset(Node* t) { 104 | if (t) 105 | t->sum = t->val; 106 | } 107 | void combine(Node*& t, Node* l, Node* r) { 108 | if (!l || !r) 109 | return void(t = l ? l : r); 110 | t->sum = l->sum + r->sum; 111 | } 112 | void operation(Node* t) { 113 | if (!t) 114 | return; 115 | reset(t); 116 | lazy(t->l); 117 | lazy(t->r); 118 | combine(t, t->l, t); 119 | combine(t, t, t->r); 120 | } 121 | void split(Node* t, Node*& l, Node*& r, int pos, int add = 0) { 122 | if (!t) 123 | return void(l = r = NULL); 124 | lazy(t); 125 | int cpos = add + sz(t->l); 126 | if (cpos <= pos) 127 | split(t->r, t->r, r, pos, cpos + 1), l = t; 128 | else 129 | split(t->l, l, t->l, pos, add), r = t; 130 | upd_sz(t); 131 | operation(t); 132 | } 133 | void merge(Node*& t, Node* l, Node* r) { 134 | lazy(l); 135 | lazy(r); 136 | if (!l || !r) 137 | t = l ? l : r; 138 | else if (l->prior > r->prior) 139 | merge(l->r, l->r, r), t = l; 140 | else 141 | merge(r->l, l, r->l), t = r; 142 | upd_sz(t); 143 | operation(t); 144 | } 145 | Node* init(int val) { 146 | Node* ret = (Node*)malloc(sizeof(Node)); 147 | ret->prior = rand(); 148 | ret->size = 1; 149 | ret->val = val; 150 | ret->sum = val; 151 | ret->lazy = 0; 152 | return ret; 153 | } 154 | int range_query(Node* t, int l, int r) { 155 | Node *left, *mid, *right; 156 | split(t, left, mid, l - 1); 157 | split(mid, t, right, r - l); /*note: r-l!*/ 158 | int ans = t->sum; 159 | merge(mid, left, t); 160 | merge(t, mid, right); 161 | return ans; 162 | } 163 | void range_update(Node* t, int l, int r, int val) { 164 | Node *left, *mid, *right; 165 | split(t, left, mid, l - 1); 166 | split(mid, t, right, r - l); /*note: r-l!*/ 167 | t->lazy += val; 168 | merge(mid, left, t); 169 | merge(t, mid, right); 170 | } 171 | }; -------------------------------------------------------------------------------- /ref/TreesCentroids.cpp: -------------------------------------------------------------------------------- 1 | #include "template.hpp" 2 | 3 | class Tree { 4 | public: 5 | struct Node { 6 | vector adjacent; Node *parent = nullptr; 7 | int start_time = 0, end_time = 0, subtree_size = 1; 8 | int depth = 0, height = 0, index = INT32_MAX; 9 | }; 10 | vector list; Node *root = nullptr; 11 | vector> __anc; 12 | Tree(int n = 1e5) { 13 | list.resize(n); this->root = &list[0]; 14 | for (int i = 0; i < n; i++) list[i].index = i; 15 | } 16 | void add_edge(int x, int y) { 17 | list[x].adjacent.push_back(&list[y]); 18 | list[y].adjacent.push_back(&list[x]); 19 | } 20 | Node *lca(Node *a, Node *b) { 21 | if (b->depth > a->depth) swap(a, b); 22 | for (int ptr = __anc[0].size() - 1; a->depth > b->depth && ptr >= 0; ptr--) 23 | if (__anc[a->index][ptr] != nullptr && 24 | __anc[a->index][ptr]->depth >= b->depth) 25 | a = __anc[a->index][ptr]; 26 | if (a == b) return a; 27 | for (long step = __anc[0].size() - 1; step >= 0; step--) 28 | if (__anc[a->index][step] != __anc[b->index][step]) 29 | a = __anc[a->index][step], b = __anc[b->index][step]; 30 | return a->parent; 31 | } 32 | Node *ancestor(Node *a, int degree) { 33 | ll target_depth = a->depth - degree; 34 | for (int ptr = __anc[0].size() - 1; a->depth > target_depth && ptr >= 0; ptr--) 35 | if (__anc[a->index][ptr] != nullptr && 36 | __anc[a->index][ptr]->depth >= target_depth) 37 | a = __anc[a->index][ptr]; 38 | return a; 39 | } 40 | int __build(Node *root = nullptr, int time = 0) { 41 | if (root == nullptr) root = this->root; 42 | root->start_time = time; 43 | for (auto child : root->adjacent) { 44 | if (child == root->parent) continue; 45 | child->parent = root; 46 | child->depth = root->depth + 1; 47 | time = __build(child, time + 1); 48 | root->height = max(root->height, child->height + 1); 49 | root->subtree_size += child->subtree_size; 50 | } 51 | root->end_time = time; 52 | return time; 53 | } 54 | void __build_lca_matrix() { 55 | int n = list.size(); 56 | __anc = *new vector>(n, vector(log2(n) + 1, nullptr)); 57 | for (int i = 0; i < list.size(); i++) __anc[i][0] = list[i].parent; 58 | for (int level = 1; level < __anc[0].size(); level++) 59 | for (int i = 0; i < list.size(); i++) { 60 | if (__anc[i][level - 1] == nullptr) continue; 61 | __anc[i][level] = __anc[__anc[i][level - 1]->index][level - 1]; 62 | } 63 | } 64 | }; 65 | 66 | struct CentroidTree : Tree { 67 | vector __visited; vector __dir_parents, __subtree_size; Tree base; 68 | void __dfs_centroid(int node) { 69 | __subtree_size[node] = 1; 70 | for (Node *next : base.list[node].adjacent) 71 | if (!__visited[next->index] && next->index != __dir_parents[node]) { 72 | __dir_parents[next->index] = node; 73 | __dfs_centroid(next->index); 74 | __subtree_size[node] += __subtree_size[next->index]; 75 | } 76 | } 77 | int __get_centroid(int x) { 78 | __dir_parents[x] = 0; __dfs_centroid(x); int sz = __subtree_size[x]; 79 | while (true) { 80 | pair mx = {0, 0}; 81 | for (Node *next : base.list[x].adjacent) 82 | if (!__visited[next->index] && next->index != __dir_parents[x]) 83 | mx = max(mx, {__subtree_size[next->index], next->index}); 84 | if (mx.first * 2 > sz) x = mx.second; else return x; 85 | } 86 | } 87 | void __build_centroid(int node, Node *parent) { 88 | node = __get_centroid(node); list[node].parent = parent; __visited[node] = true; 89 | for (Node *next : base.list[node].adjacent) 90 | if (!__visited[next->index]) __build_centroid(next->index, &list[node]); 91 | } 92 | CentroidTree(Tree &tree) : Tree((int)tree.list.size()) { 93 | __visited = vector(tree.list.size()); 94 | __subtree_size = vector(tree.list.size()); 95 | __dir_parents = vector(tree.list.size()); 96 | base = tree; 97 | __build_centroid(0, nullptr); 98 | for (auto el : list) { 99 | if (el.parent == nullptr) root = &list[el.index]; 100 | else add_edge(el.index, el.parent->index); 101 | } __build(root); 102 | } 103 | }; 104 | 105 | ll diameter(Tree tree) { 106 | ll n = tree.list.size() + 1; vbl visited(n + 1, false); vll distances(n + 1, -1); 107 | queue q; q.push({tree.root->index, 0}); 108 | ll node_max = tree.root->index, distance_max = 0; 109 | while (!q.empty()) { 110 | auto node = q.front(); q.pop(); 111 | if (node.second < distance_max) distance_max = node.second, node_max = node.first; 112 | for (auto neighbor : tree.list[node.first].adjacent) 113 | if (!visited[neighbor->index]) { 114 | auto d = node.second + 1; 115 | q.push({neighbor->index, d}); 116 | visited[neighbor->index] = 1; 117 | } 118 | } 119 | visited = vbl(n + 1, false); 120 | q.push({node_max, 0}); distance_max = 0; 121 | while (!q.empty()) { 122 | auto node = q.front(); q.pop(); 123 | maximize(distance_max, node.second); 124 | for (auto neighbor : tree.list[node.first].adjacent) 125 | if (!visited[neighbor->index]) { 126 | auto d = node.second + 1; 127 | q.push({neighbor->index, d}); 128 | visited[neighbor->index] = 1; 129 | } 130 | } 131 | } 132 | 133 | struct HeavyLightDecomp : Tree { 134 | int chain_count = 1, narr; 135 | vector subtree_size, chain, chain_head, chain_next; 136 | function answer; 137 | vector pos; 138 | 139 | HeavyLightDecomp(int n, function &ans) : Tree(n) { 140 | subtree_size.resize(n); pos.resize(n); chain.resize(n); 141 | chain_head.resize(n); chain_next.resize(n); answer = ans; 142 | } 143 | 144 | void decompose(int node = 0, int parent = -1) { 145 | pos[node] = ++narr, chain[node] = chain_count; int big = 0; 146 | for (Node *adj : list[node].adjacent) { 147 | int u = adj->index; 148 | if (u == parent) continue; 149 | else if (!big) big = u; 150 | else if (subtree_size[u] > subtree_size[big]) big = u; 151 | } 152 | if (big) decompose(big, node); 153 | for (Node *adj : list[node].adjacent) { 154 | int u = adj->index; 155 | if (u == parent || u == big) continue; 156 | ++chain_count, chain_head[chain_count] = u, 157 | chain_next[chain_count] = node; 158 | decompose(u, node); 159 | } 160 | } 161 | // Build Segment Tree using indices of pos array 162 | // Update ans using Range queries on said segment tree 163 | int query_up(int r, int q) { 164 | int ans = 0, t; 165 | while (chain[q] != chain[r]) { 166 | t = chain[q]; 167 | ans = answer(pos[chain_head[t]], pos[q], ans); 168 | q = chain_next[t]; 169 | } 170 | ans = answer(pos[r], pos[q], ans); 171 | return ans; 172 | } 173 | }; -------------------------------------------------------------------------------- /ref/_team_reference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/ref/_team_reference.pdf -------------------------------------------------------------------------------- /ref/generate.sh: -------------------------------------------------------------------------------- 1 | # sudo apt-get install texlive 2 | # sudo npm install -g notebook-generator 3 | 4 | notebook-generator ./ -s 10 -a "ACLimitExceeded (Animesh Sinha, Gaurang Tandon, Arpan Dasgupta)" --output _team_reference.pdf -i "ACLimitExceeded" 5 | -------------------------------------------------------------------------------- /ref/team.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AnimeshSinha1309/algorithms-notebook/80b7fc2cdc0a85aa26d41fb87697e2363b057bf5/ref/team.pdf -------------------------------------------------------------------------------- /ref/template.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | typedef long long ll; 5 | typedef vector vll; 6 | typedef pair pll; 7 | typedef vector> mll; 8 | typedef vector> vpl; 9 | typedef long double ld; 10 | typedef vector vld; 11 | typedef vector> mld; 12 | typedef vector vbl; 13 | typedef vector> mbl; 14 | typedef complex cd; 15 | typedef vector> vcd; 16 | #define minimize(a, b) (a = min(a, b)) 17 | #define maximize(a, b) (a = max(a, b)) 18 | const long long MOD = 1e9 + 7; 19 | 20 | #pragma GCC optimize("Ofast") 21 | #pragma GCC optimize("unroll-loops") 22 | #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native") 23 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | oj --version 4 | 5 | CXX=${CXX:-g++} 6 | CXXFLAGS="${CXXFLAGS:--std=c++14 -O2 -Wall -g}" 7 | ulimit -s unlimited # make the stack size unlimited 8 | 9 | # list files to test 10 | for file in $(find . -name \*.test.cpp) ; do 11 | # get the URL for verification 12 | url="$(sed -e 's/^# *define \+TURL \"\+\(https\?:\/\/.*\)\"/\1/ ; t ; d' "$file")" 13 | echo "Testing $file obtained url $url" 14 | 15 | if [[ -z ${url} ]] ; then 16 | continue 17 | fi 18 | 19 | dir=cache/$(echo -n "$url" | md5sum | sed 's/ .*//') 20 | mkdir -p ${dir} 21 | 22 | # download sample cases 23 | if [[ ! -e ${dir}/test ]] ; then 24 | sleep 2 25 | oj download --system "$url" -d ${dir}/test 26 | fi 27 | 28 | # run test 29 | $CXX $CXXFLAGS -I . -o ${dir}/a.out "$file" 30 | oj test --tle 10 --c ${dir}/a.out -d ${dir}/test 31 | done 32 | -------------------------------------------------------------------------------- /tests/BellmanFord.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_B" 2 | 3 | #include "../code/Graphs.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n, m, s; 11 | cin >> n >> m >> s; 12 | Graph g(n); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v, w; 15 | cin >> u >> v >> w; 16 | g.add_edge(u, v, w, false); 17 | } 18 | // Get the result from a call to Bellman Ford 19 | pair res = g.bellman_ford({s}); 20 | // Print the outputs 21 | for (int i = 0; i < n; i++) { 22 | if (res.first[i] == INT64_MIN) { 23 | cout << "NEGATIVE CYCLE" << endl; 24 | return 0; 25 | } 26 | } 27 | for (int i = 0; i < n; i++) { 28 | if (res.first[i] == INT64_MAX) 29 | cout << "INF" << endl; 30 | else 31 | cout << res.first[i] << endl; 32 | } 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /tests/Dijkstra.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_A" 2 | 3 | #include "../code/Graphs.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n, m, s; 11 | cin >> n >> m >> s; 12 | Graph g(n); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v, w; 15 | cin >> u >> v >> w; 16 | g.add_edge(u, v, w, false); 17 | } 18 | // Get the result from a call to Dijkstra 19 | pair res = g.dijkstra({s}); 20 | // Print the outputs 21 | for (int i = 0; i < n; i++) { 22 | if (res.first[i] == INT64_MAX) 23 | cout << "INF" << endl; 24 | else 25 | cout << res.first[i] << endl; 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /tests/Dinics.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_6_A" 2 | 3 | #include "../code/FlowAlgorithms.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n, m; 11 | cin >> n >> m; 12 | Dinic g(n); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v, w; 15 | cin >> u >> v >> w; 16 | g.add_edge(u, v, w); 17 | } 18 | // Get the result from a call to Dijkstra 19 | ll res = g.max_flow(0, n - 1); 20 | // Print the outputs 21 | cout << res << endl; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /tests/DisjointSet.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_1_A" 2 | 3 | #include "../code/DisjointSet.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | int n, q; 10 | cin >> n >> q; 11 | DisjointSetTree dsu(n); 12 | while (q--) { 13 | int com, x, y; 14 | cin >> com >> x >> y; 15 | if (com == 0) { 16 | dsu.merge(x, y); 17 | } else if (com == 1) { 18 | cout << (dsu.find(x) == dsu.find(y)) << endl; 19 | } 20 | } 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/FloydWarshall.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_1_C" 2 | 3 | #include "../code/Graphs.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n, m; 11 | cin >> n >> m; 12 | Graph g(n); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v, w; 15 | cin >> u >> v >> w; 16 | g.add_edge(u, v, w, false); 17 | } 18 | // Get the result from a call to Floyd Warshall 19 | mll res = g.floyd_warshall(); 20 | // Print the outputs 21 | for (int i = 0; i < n; i++) { 22 | if (res[i][i] < 0) { 23 | cout << "NEGATIVE CYCLE" << endl; 24 | return 0; 25 | } 26 | } 27 | for (int i = 0; i < n; i++) { 28 | for (int j = 0; j < n; j++) { 29 | if (res[i][j] == INT64_MAX) 30 | cout << "INF"; 31 | else 32 | cout << res[i][j]; 33 | if (j != n - 1) 34 | cout << " "; 35 | } 36 | cout << endl; 37 | } 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/HopkroftKarp.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_7_A" 2 | 3 | #include 4 | 5 | #include "../code/FlowAlgorithms.hpp" 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n_x, n_y, m; 11 | cin >> n_x >> n_y >> m; 12 | HopcroftKarp g(n_x, n_y); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v; 15 | cin >> u >> v; 16 | g.add_edge(u, v); 17 | } 18 | // Get the result from a call to Dijkstra 19 | ll res = g.max_match(); 20 | // Print the outputs 21 | cout << res << endl; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /tests/PushRelabel.test.cpp: -------------------------------------------------------------------------------- 1 | #define TURL "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_6_A" 2 | 3 | #include "../code/FlowAlgorithms.hpp" 4 | 5 | #include 6 | using namespace std; 7 | 8 | int main() { 9 | // Prepare the Graph 10 | int n, m; 11 | cin >> n >> m; 12 | PushRelabel g(n); 13 | for (int i = 0; i < m; i++) { 14 | ll u, v, w; 15 | cin >> u >> v >> w; 16 | g.add_edge(u, v, w); 17 | } 18 | // Get the result from a call to Dijkstra 19 | ll res = g.max_flow(0, n - 1); 20 | // Print the outputs 21 | cout << res << endl; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /tests/tests_status.md: -------------------------------------------------------------------------------- 1 | # Status of Testing 2 | 3 | ## Completely Tested Methods 4 | 5 | * Graph Class 6 | * Floyd Warshall - Has been tested both for distances and negative loop 7 | 8 | ## Partially Tested Methods 9 | 10 | * Graph Class 11 | * Dijkstra's Algorithm - Has been tested for outputting correct distances, not for correct path 12 | * Bellman Ford's Algorithm - Has been tested for outputting correct distances, not for correct path 13 | 14 | ## In the Test Queue 15 | 16 | A lot of methods will be added, when we are close to finishing up, we will add all the new methods here. 17 | -------------------------------------------------------------------------------- /tex/_strategysheet.tex: -------------------------------------------------------------------------------- 1 | \chapter{Problem Solving Strategies} 2 | 3 | 4 | \section{General Advice and Basic Patters} 5 | 6 | \begin{itemize} 7 | \item If you need to Minimize a Maximum or Maximize a Minimum, use Binary Search. 8 | \begin{enumerate} 9 | \item \href{https://www.codechef.com/KH19MOS/problems/ANAJOBS}{ICPCkh19-ANAJOBS} 10 | \end{enumerate} 11 | \item If you want to use DP / Expectation to find something optimal, use Exchange Argument. 12 | \begin{enumerate} 13 | \item \href{https://www.codechef.com/GWR17ROL/problems/KALADIN}{ICPCgw17-KALADIN} 14 | \end{enumerate} 15 | \end{itemize} 16 | 17 | 18 | \section{Standard Problems for Practice} 19 | 20 | \subsection{Math and Geometry} 21 | 22 | \begin{itemize} 23 | \item Substitutions can help reduce the dimentionality of the problem (Kernel trick). 24 | \begin{enumerate} 25 | \item \href{https://codeforces.com/problemset/problem/1142/C}{CF1142-C}: Make the Substitution $z_{i} = y_{i}^{2} - x_{i}$. Now the problem is just computing the upper convex hull. 26 | \end{enumerate} 27 | \end{itemize} 28 | 29 | \section{Trees and Graphs} 30 | 31 | \begin{itemize} 32 | \item Substitutions can help reduce the dimentionality of the problem (Kernel trick). 33 | \begin{enumerate} 34 | \item \href{https://codeforces.com/problemset/problem/1142/C}{CF1142-C}: Nice use of LCA for finding. 35 | \end{enumerate} 36 | \item On shortest paths with pay-for-ticket/earn-by-staying, expand state space and use Dijkstra. 37 | \begin{enumerate} 38 | \item \href{https://atcoder.jp/contests/abc164/tasks/abc164_e}{ABC164-E} Simple idea with one constraint. 39 | \item \href{https://codeforces.com/contest/1341/problem/E}{CF1341-E}: Uses 0-1 BFS to speed up. 40 | \end{enumerate} 41 | \end{itemize} 42 | 43 | -------------------------------------------------------------------------------- /tex/dynamicprogramming.tex: -------------------------------------------------------------------------------- 1 | \chapter{Dynamic Programming} 2 | 3 | The focus of this chapter would be to enlist all the optimizations to a DP possible and types of recurrences solvable using them. 4 | 5 | 6 | 7 | \section{Matrix Exponentiation} 8 | 9 | 10 | \begin{example}[DP by Matrix Exponentiation]{exm-dp-matrix-expo-1} 11 | \textbf{Number of ways to construct an array starting in X, and ending in Y, with no two adjacent elements are the same.} 12 | \begin{equation*} 13 | dp[i] = \begin{bmatrix} dp[i][\text{CLASH}] \\ dp[i][\text{CLEAN}] \end{bmatrix} 14 | = \begin{bmatrix} 0 & 1 \\ k-1 & k-2 \end{bmatrix} \times dp[i-1] 15 | \end{equation*} 16 | \end{example} 17 | 18 | 19 | \section{Bitmasks} 20 | 21 | 22 | \subsection{Classical Bitmasks} 23 | 24 | The idea is trivial, we take each bitmask to represent an arbitrary subset of any given set. 25 | 26 | 27 | \subsection{Sum over Subsets} 28 | 29 | We want to sum for each mask, some given function (as an array) for all it's submasks. 30 | We can take each mask to start off, and then go down a series of all it's subsets in decreasing order of value of mask, the algorithm for this will be $j = (j - 1)\;\&\;mask$, initially $j_0 = mask$. 31 | 32 | Time complexity is the following: 33 | \begin{equation} 34 | T(n) = \sum_{k=0}^{n-1} C^n_k 2^k = 3^k 35 | \end{equation} 36 | -------------------------------------------------------------------------------- /tex/flows.tex: -------------------------------------------------------------------------------- 1 | \chapter{Flow Algorithms} 2 | 3 | 4 | 5 | \section{Some interesting types of Flows} 6 | 7 | \subsection{Circulation Flows} 8 | 9 | When there is no source, but we need to find if there exists a valid cyclic flow in a graph with directed edges with minimum and maximum capacities. The flow through each pipe has to be more than minimum and less than maximum. 10 | 11 | 12 | 13 | \section{Chains in Posets} 14 | 15 | A Poset (Partially Ordered Set) is a set where $<$, $=$, $>$ are defined between some pair of elements but not over others. A subset where comparators are defined between every pair is called a chain, where none is defined is called an anti-chain. 16 | 17 | \begin{theorem}[Dilworth's Theorem]{thm:dilworth-theorem} 18 | The maximum length of any anti-chain in a poset equals the number of chains in it's minimal chain cover. 19 | \end{theorem} 20 | 21 | \begin{theorem}[Koenig's Theorem]{thm:koenig-theorem} 22 | The minimum set cover of a bipartite graph equals the maximum flow from one set to the other. 23 | \end{theorem} -------------------------------------------------------------------------------- /tex/gametheory.tex: -------------------------------------------------------------------------------- 1 | \chapter{Game Theory} 2 | 3 | 4 | 5 | \section{NIM Games and Sprague-Grundy Theorem} 6 | 7 | 8 | 9 | \section{Take Away Games} 10 | 11 | 12 | \subsection{Identifying the Losing States} 13 | 14 | \begin{theorem}{Take Away} 15 | Let $H_i$ denote all the losing states, and $f(x)$ denote the number of stones that can be removed in the next move after x stones in the previous. Then we can find the losing states as follows. 16 | \begin{equation} 17 | H_{k+1} = H_k + H_m, \;\;\;\;\; where \;\; m = min \{j: f(H_j) \geq H_k\} 18 | \end{equation} 19 | \end{theorem} 20 | The idea is that we can remove any $H_j + H_k$ stones, we can think of them as two separate piles. We cannot win on either pile, so the only way to win is when the $H_j$ pile ends, the last move was enough that $f(last\:move) \geq H_k$ so that we can win next move. If this is not possible, then the state is losing. 21 | 22 | \textbf{KEY IDEA: Find the RECURRENCE, make a SOLUTION HYPOTHESIS by monitoring the pattern and prove it BY INDUCTION to get all the losing states.} 23 | 24 | 25 | \subsection{A few Example Functions} 26 | 27 | \subsubsection{Example: f(x) = x} 28 | 1 stone is losing, so $H_1 = 1$. And whenever $H_k$ is losing, the $min\{H_j : f(H_j) \geq H_k\} = min\{H_j : H_j \geq H_k\} = H_k$, therefore the losing states are $2^n$. 29 | \subsubsection{Example: f(x) = 2x - 1} 30 | 1 stone is losing, so $H_1 = 1$. Our Hypothesis, $H_k = 2 H_{k-1}$. And whenever $H_k$ is losing, the $min\{H_j : f(H_j) \geq H_k\} = min\{H_j : 2*H_j-1 \geq H_k\} = H_k$, therefore the losing states are $2^n$. 31 | \subsubsection{Example: f(x) = 2x: Fibonacci NIM} 32 | 1 stone is losing, so $H_1 = 1$. Our Hypothesis, $H_k = H_{k-1} + H_{k-2}$. And whenever $H_k$ is losing, the $min\{H_j : f(H_j) \geq H_k\} = min\{H_j : 2*H_j \geq H_k\} = H_{k-1}$, therefore the losing states are the Fibonacci numbers. 33 | 34 | 35 | \subsection{Winning Strategy} 36 | 37 | \subsubsection{New Binary number systems} 38 | We find that we can express any number as a sum of the values of $H_1$, $H_2$, ..., so we construct a binary like number system where a the place value of the i-th digit is $H_i$ and the face value is 0 or 1. Let's call this H-binary. (Note: This expression is unique and complete for powers of 2, and for the Fibonacci numbers - Zeckendorf theorem, as in the above examples). 39 | 40 | \subsubsection{The greedy strategy} 41 | 42 | Given any starting state that is not losing, we can write out it's representation in the H-Binary system. 43 | Since this will have more than 1 ones in it's representation, \colorbox{yellow}{we subtract the LEAST SIGNIFICANT BIT}. 44 | 45 | Now, the opponent cannot remove the next one in the representation, because of the property of number systems that $H_j > f(H_i) \;\; \forall j > i$, due to the way we found losing states $H_i$. Finally, when our oppnent removes any value from the form $.....1000000$ (Any value, last set bit 1, and 0s), he will get a 1 in the resulting representation $.....0000110$. 46 | 47 | Now in our move we shall remove the lowest set bit again. This is possible, as the last move must have been greater than or equal to $H_j$ if j is lowest set bit. (Obviously, because when we add back we need to have 1+1 = 0 to get all the numbers back to 0 and 1 at the position that could not be removed). So $f(H_j) >= H_j$, this move is possible, and we can win. 48 | 49 | \subsection{Proof of Victory} 50 | On our moves, we reduce the number of ones in the representation by 1. Our opponent, if he removes the one at $H_j$, he has to insert a 1 and position smaller than j. So he increases or keeps constant the number of ones. Obviously, the last move will be played by us, reducing the number of ones to 0 and finishing the game. 51 | 52 | 53 | \subsection{References} 54 | 55 | \subsubsection{Problems} 56 | Fibonacci Nim (Direct Implementation) [ICPC Kolkata 2018] \url{https://www.codechef.com/KOL18ROL/problems/SNOWMAN} 57 | 58 | \subsubsection{Theory} 59 | Contains most of the theory mentioned above: \url{http://www.cut-the-knot.org/Curriculum/Games/TakeAway.shtml#theory} 60 | 61 | 62 | 63 | \section{Finding Invarients} 64 | 65 | \textbf{Mark out a state and all it's children. Either try MINIMAX TREE, and if the state space is large, try to find invarients, specially MODULO or PARITY.} 66 | 67 | \begin{example}[Invarients in Games - 1]{exm:invarients-stick-game-1} 68 | \textbf{Question: Start with \{(4 sticks, length 4), (1 stick, length 1)\}. In a move, we can break a stick or remove k sticks of length k. Last move wins. Find the winning states \& strategy.} 69 | Any state be (n1, n2, n3, n4). All states with (n1 + n3) \% 2 == (n2 + n4) \% 3 are winning positions, all others are losing. We can prove than any winning position goes to losing position and vice-versa. 70 | \end{example} 71 | -------------------------------------------------------------------------------- /tex/graphstrees.tex: -------------------------------------------------------------------------------- 1 | \chapter{Graphs and Tree} 2 | 3 | 4 | 5 | \section{Trees} 6 | 7 | 8 | \subsection{Heavy Light Decomposition} 9 | 10 | \subsubsection{Motivating Problem} 11 | 12 | Given a Tree, handle the following queries: 13 | \begin{itemize} 14 | \item Update(edge, weight): Change the weight of any given edge in the Tree. 15 | \item Query(nodeX, nodeY): Find the heaviest eadge between two nodes, x and y. 16 | \end{itemize} 17 | 18 | \begin{figure}[h] 19 | \begin{center} 20 | \includegraphics[scale=0.2]{img/heavy-light-decomposition.png} 21 | \end{center} 22 | \caption{Heavy Light decomposition of a Tree} 23 | \end{figure} 24 | 25 | 26 | \section{Basic Algorithms on Graphs} 27 | 28 | 29 | \subsection{List of algorithms} 30 | 31 | \begin{itemize} 32 | \item Depth First Search 33 | \item Breadth First Search 34 | \item Shortest Path - Dijkstra's 35 | \item Shortest Path - Bellman Ford 36 | \item Shortest Path - Floyd Warshall 37 | \item Connected Components 38 | \item Topological Sort 39 | \item Prim's Maximum Spanning Tree 40 | 41 | \end{itemize} 42 | 43 | 44 | \subsection{Code} 45 | 46 | \lstinputlisting[basicstyle=Large,style=cpp]{code/Graphs.hpp} -------------------------------------------------------------------------------- /tex/probability.tex: -------------------------------------------------------------------------------- 1 | \chapter{Probability} 2 | 3 | 4 | 5 | \section{Methods of Solving Problems} 6 | 7 | All Probability or Expectation Value problems are solvable using these techniques, so trying to classify all problems in one of the following is reasonable. 8 | 9 | \subsubsection{Probability times Value (The Definition)} 10 | 11 | Expectation by Definition is Probability times the Value of the event. If the state space is ennumerable, then this is the technique to go with. Sometimes, \textbf{Dynamic Programming} can be used with this technique. 12 | 13 | \subsubsection{Technique of Contributions (Exchange Argument)} 14 | 15 | For each element, find what is the Probability that it contributes to the total answer, and how much does it contribute. Try to solve for every pair of elements, then take it to all the elements. 16 | 17 | \subsubsection{Indicator Variables} 18 | 19 | Interconverting sums using indicator variables is often a hard and algebraically tedious topic, hence we mark it as a \#TODO. 20 | 21 | 22 | \section{Problems and Solutions} 23 | 24 | 25 | \subsection{Codeforces 100371-H: Granite of Science} 26 | 27 | \begin{problem}[Granite of Science]{prob:CF100371H} 28 | There are $n$ subjects, each having $n_i$ lessons. Let the lessons be indexed by $j$. We are looking at the first $m$ days of the semester. Any subject can start on any of the m days (even if all it's lesson's don't fit till the end), and each lesson will follow consecutively and contigously. Given that $h_{i,j}$ is the fatigue due to i-th subject's j-th lesson, and effective fatigue in one day is the sum of squares of fatigues due to all lessons that day. Total Fatigue is sum of effective fatigue in each of m days. Compute expected total fatigue. 29 | 30 | \colorbox{green}{Tags}: 2D Prefix Sum , Linearity of Expectation, Independent Events. 31 | \end{problem} 32 | 33 | Following is one solution to this problem (simplest and cleanest). Another one using Indicator Variables also exists, but seems to overcomplicate a relatively simple question. 34 | 35 | 36 | Notation: $n$ is number of subjects. $f_{\text{day}}$ is the sum of difficulties of all subjects on that day. $f_{\text{day}} = \sum_{i=1}^{i}d_i,j$, where $d_i$ is difficulty of i-th subject for that particular day and j-th lesson. 37 | 38 | \begin{eqnarray*} 39 | \text{ans} &=& \sum_{\text{day}=1}^{n} f_{\text{day}}^2 \\ 40 | \implies E[\text{ans}] &=& E\left[\sum_{\text{day}=1}^{2m}f_{\text{day}}^2 \right] \\ 41 | &=& \sum_{\text{day}=1}^{2m}E\left[f_{\text{day}}^2\right] \\ 42 | \end{eqnarray*} 43 | 44 | Now, $f_{\text{day}}^2 = (c_1+c_2+\ldots+c_n)^2=(\sum_{i}c_i^2 + 2\sum_{i,j; i\ne j}c_ic_j)$ 45 | 46 | \begin{eqnarray*} 47 | E\left[f_{\text{day}}^2\right]&=&\sum_{i}E[c_i^2] + 2\sum_{i,j; i\ne j}E[c_ic_j] \\ 48 | &=& \sum_{i}E[c_i^2] + 2\sum_{i,j; i\ne j}E[c_i]E[c_j] 49 | \end{eqnarray*} 50 | 51 | Because $i$-th and $j$-th subject's contribution on the same day are independent of each other, their expectations can be split. The final expression can be simplified using the following: 52 | 53 | \begin{eqnarray*} 54 | 2\sum_{i,j; i\ne j}E[c_i]E[c_j] = \sum_{i,j}E[c_i]E[c_j] - \sum_{i}E[c_i]^2 55 | \end{eqnarray*} 56 | 57 | Thus, now we can use prefix sums and solve this problem in $\mathcal{O}(N^2)$. 58 | -------------------------------------------------------------------------------- /tex/rangequeries.tex: -------------------------------------------------------------------------------- 1 | \chapter{Range Queries} 2 | 3 | 4 | 5 | \section{Square Root Decomposition} 6 | 7 | Break the array down into chunks of $\sqrt{n}$. Store the answer to these chunks. The answer to range queries is the answer in the starting chunk after L, plus in the ending chunk before R, plus the stored results of everything in between. Updates can be done in $O(\sqrt{n})$ steps by just updating the result of the chunk. 8 | 9 | \subsection{Motivating Examples} 10 | 11 | This cannot be solved by a Segment Tree (easily). 12 | 13 | \begin{example}{q-rmq-01} 14 | \textbf{Question: Given and array, support update and query operation for number of elements less than k in the given range.} \\ 15 | Solution: Maintain sorted vector of each block of the square-root decomposition. Search over all blocks and find lowerbound(k), the sum of these counts gives the answer in $O(\sqrt{n} log(n))$. For update, just sort again, using insertion sort you get $O(\sqrt{n})$. 16 | \end{example} 17 | 18 | 19 | 20 | \section{Mo's Algorithm} 21 | 22 | This is an algorithm to handle offline queries by sorting them and trying to cleverly avoid recomputing portions that were already solved \relax for in the previous queries. 23 | (Direcly usable with associative, commutative, invertible operations). 24 | 25 | \subsubsection{Algorithm} 26 | Break down the array in blocks of size $\sqrt{n}$. Sort queries by starting block, them by ending position. The right pointer keeps moving forward for each block, the left pointer keeps moving back and forth withing a block, adding elements as it goes back and subtracting as it goes forth. This results in all queries being solved in $O(n\sqrt{n})$ time. 27 | 28 | \begin{example}{q-rmq-02} 29 | \textbf{Question: Given an array, find the number of elements distinct elements in range (l, r).} 30 | Sort the queries first by the starting block, then by the end position. Maintian a frequency array of all elements currently between right and left pointers. For each of the $O(\sqrt{n})$ blocks, the start pointer moves atmost $O(\sqrt{n})$ times back and forth in the block, adding and deleting elements. For each block the right pointer only goes forward adding in elements, $O(\sqrt{n})$ blocks each taking $O(n)$ time. 31 | \end{example} 32 | 33 | \begin{example}{q-rmq-03} 34 | \textbf{Question: Given an array, find the f(s)*f(s)*s for all distinct s in range (l, r), where f(s) is the frequency of s.} \\ 35 | Same Algorithm, and same frequency array as above, just find $f(s)*f(s)*s$ instead of $\delta(f(s))$ as above. 36 | \end{example} 37 | 38 | 39 | 40 | \section{Segment Trees} 41 | 42 | \subsection{Iterative Implementation} 43 | 44 | \lstinputlisting[basicstyle=Large,style=cpp]{code/SegmentTree.hpp} -------------------------------------------------------------------------------- /tex/stackqueueheap.tex: -------------------------------------------------------------------------------- 1 | \chapter{Heaps} 2 | 3 | 4 | 5 | \section{Question Patterns} 6 | 7 | 8 | \subsection{Generic Types} 9 | 10 | \begin{itemize} 11 | \item Find the kth Minimum or Maximum. This can also be on arrays or trees with online insertion or deletion. 12 | \item Priority Queue questions. Typically greedy algorithms best implemented this way. (eg. Dijkstra) 13 | \end{itemize} 14 | 15 | 16 | \subsection{Specific Illustrations} 17 | 18 | \paragraph{When not to use Heaps} \textit{Question: Find the kth-Maximum sum of all subarrays of any given array}. This question demostrates that when we have \textbf{k-sorted elements appended to our queue of k-maximum elements} at one go, it's better to use an actual \textbf{Sorted array and the Merge Function for Updates}. 19 | 20 | \paragraph{Lazy Deletion} Heaps cannot search, so heaps cannot delete. A simple solution for this is to maintain another heap of all deleted elements, and if the actual heap and deleted heap have the same top element, keep popping them out. We only care about the top element, so we can be Lazy in the deletion of the elements lower down in the tree. 21 | 22 | 23 | 24 | \section{Elementary Theory} 25 | 26 | 27 | \subsection{Basic Operations} 28 | 29 | \paragraph{Heapification} 30 | A \textbf{O(n)} algorithm exists for Heapification. It uses the standard sift-down procedure, but starts by correcting the lowest layers first. So start at the end of the array and move back. 31 | 32 | \paragraph{Insert} 33 | A \textbf{O(log n)} algorithm is used to insert. We push the element at the end of the array and sift-up or sift-down the element till the element is at a valid locale. 34 | 35 | \paragraph{Delete} 36 | For a \textbf{O(log n)} deletion algorithm, we must swap the last element with the element to be deleted, sift-up/down the former last element, and pop-out the last element. 37 | This is only possible if we have a refernce to the element, search and delete take O(n) time to perform on heaps. 38 | 39 | \paragraph{Minimum/Maximum} 40 | Minimum on a MinHeap takes \textbf{O(1)} time, and so does Maximum on a MaxHeap. 41 | 42 | \subsection{Implementation Code} 43 | 44 | \lstinputlisting[basicstyle=Large,style=cpp]{code/BinaryHeap.hpp} --------------------------------------------------------------------------------