├── .vscode └── settings.json ├── Contest Template ├── brute.cpp ├── checker.sh ├── gen.cpp └── main.cpp ├── Data Structures ├── DSU.cpp ├── Fenwick Tree │ ├── 2D Fenwick Tree.cpp │ ├── Fenwick Tree (order statistic tree).cpp │ ├── Fenwick Tree (point update, range query).cpp │ ├── Fenwick Tree (range update, point query).cpp │ └── Fenwick Tree (range update, range query).cpp ├── HLD.cpp ├── PBDS.cpp ├── SQRT.cpp ├── Segment Tree │ ├── Advanced example 1.cpp │ ├── Advanced example 2.cpp │ ├── Advanced example 3.cpp │ ├── Segment Tree (Lazy Propagation).cpp │ ├── Segment Tree (Persistent).cpp │ ├── Segment Tree (Recursive).cpp │ └── Segment Tree Beats.cpp ├── Sparse Table.cpp ├── Suffix Array.cpp ├── Treap.cpp ├── Tree Query.cpp └── Trie.cpp ├── Dynamic Programming ├── (0-1) Knapsack.cpp ├── 1D Max Sum (Kanade).cpp ├── 2D Max Sum.cpp ├── Coin Change.cpp ├── Convex Hull Trick & Li-Chao Segment Tree.cpp ├── Cutting Sticks.cpp ├── D&C Trick.cpp ├── Deque Trick.cpp ├── Digit DP.cpp ├── Elevator Rides.cpp ├── Longest Common Subsequence (LCS).cpp ├── Longest Increasing Subsequence (LIS).cpp ├── Matrix Chain.cpp ├── SOS DP.cpp ├── Traveling Salesman Problem (TSP).cpp └── Weighted Job Scheduling.cpp ├── Geometry ├── Basic.cpp └── Sweep Line │ ├── Closest Pairs.cpp │ └── Rectangle Union.cpp ├── Graphs ├── Graph Traversal │ ├── BFS.cpp │ ├── Bipartite.cpp │ ├── DFS.cpp │ └── Flood Fill.cpp ├── Lowest Common Ancestor │ ├── LCA (Binary Lifting).cpp │ ├── LCA (RMQ).cpp │ └── README.md ├── Max Flow │ ├── Dinic.cpp │ └── Edmonds_Karp.cpp ├── Minimum Spanning Tree │ ├── Kruskal.cpp │ ├── Prim.cpp │ └── README.md ├── Shortest Paths │ ├── 0-1 BFS.cpp │ ├── Bellman_Ford.cpp │ ├── Dijkstra.cpp │ ├── Floyd_Warshall.cpp │ └── README.md ├── Strongly Connected Components (SSCs) │ ├── Advanced example.cpp │ ├── Bridges&ArticulationPoints.cpp │ ├── Kosaraju.cpp │ └── Tarjan.cpp └── Topological Sort │ ├── README.md │ ├── Topological Sort (DFS).cpp │ └── Topological Sort (in_deg).cpp ├── LICENSE ├── Mathematics ├── Binomial Coefficients.cpp ├── Fibonacci.cpp ├── GCD.cpp ├── Quick Exponention.cpp └── Sieve Of Eratosthenes.cpp ├── Others ├── 2SAT.cpp ├── Closest_3_Points(Divide&Conquer).cpp ├── Maximum Histogram Area (Monotonic Stack).cpp ├── Median Heap.cpp ├── Meet In The Middle.cpp ├── N Queens.cpp └── Offline Dynamic Connectivity.cpp ├── README.md ├── String Processing ├── KMP (Prefix function).cpp ├── String Hashing (Rabin-Karp).cpp └── Z-algo (Z function).cpp ├── _config.yml └── snippets.json /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "iostream": "cpp", 4 | "chrono": "cpp" 5 | }, 6 | "C_Cpp.errorSquiggles": "Disabled" 7 | } -------------------------------------------------------------------------------- /Contest Template/brute.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template ostream& operator<<(ostream &os, const pair &p) { return os << '(' << p.first << ", " << p.second << ')'; } 6 | template::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) { os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; } 7 | void dbg_out() { cerr << endl; } 8 | template void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } 9 | #ifdef LOCAL 10 | #define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) 11 | #else 12 | #define dbg(...) 13 | #endif 14 | 15 | #define ar array 16 | #define ll long long 17 | #define ld long double 18 | #define sza(x) ((int)x.size()) 19 | #define all(a) (a).begin(), (a).end() 20 | 21 | const int MAX_N = 1e5 + 5; 22 | const ll MOD = 1e9 + 7; 23 | const ll INF = 1e9; 24 | const ld EPS = 1e-9; 25 | 26 | 27 | 28 | void solve() { 29 | 30 | } 31 | 32 | int main() { 33 | ios_base::sync_with_stdio(0); 34 | cin.tie(0); cout.tie(0); 35 | int tc = 1; 36 | // cin >> tc; 37 | for (int t = 1; t <= tc; t++) { 38 | // cout << "Case #" << t << ": "; 39 | solve(); 40 | } 41 | } -------------------------------------------------------------------------------- /Contest Template/checker.sh: -------------------------------------------------------------------------------- 1 | for((i = 1; i <= 20; i++)) do 2 | echo "Test $i" 3 | ./gen > in 4 | diff -w <(./main < in) <(./brute < in) || break 5 | done -------------------------------------------------------------------------------- /Contest Template/gen.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template ostream& operator<<(ostream &os, const pair &p) { return os << '(' << p.first << ", " << p.second << ')'; } 6 | template::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) { os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; } 7 | void dbg_out() { cerr << endl; } 8 | template void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } 9 | #ifdef LOCAL 10 | #define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) 11 | #else 12 | #define dbg(...) 13 | #endif 14 | 15 | #define ar array 16 | #define ll long long 17 | #define ld long double 18 | #define sza(x) ((int)x.size()) 19 | #define all(a) (a).begin(), (a).end() 20 | 21 | const int MAX_N = 1e5 + 5; 22 | const ll MOD = 1e9 + 7; 23 | const ll INF = 1e9; 24 | const ld EPS = 1e-9; 25 | 26 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 27 | ll rand(ll l, ll r) {return uniform_int_distribution(l, r)(rng);} 28 | 29 | int main() { 30 | ios_base::sync_with_stdio(0); 31 | cin.tie(0); cout.tie(0); 32 | } 33 | -------------------------------------------------------------------------------- /Contest Template/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | template ostream& operator<<(ostream &os, const pair &p) { return os << '(' << p.first << ", " << p.second << ')'; } 6 | template::value, typename T_container::value_type>::type> ostream& operator<<(ostream &os, const T_container &v) { os << '{'; string sep; for (const T &x : v) os << sep << x, sep = ", "; return os << '}'; } 7 | void dbg_out() { cerr << endl; } 8 | template void dbg_out(Head H, Tail... T) { cerr << ' ' << H; dbg_out(T...); } 9 | #ifdef LOCAL 10 | #define dbg(...) cerr << "(" << #__VA_ARGS__ << "):", dbg_out(__VA_ARGS__) 11 | #else 12 | #define dbg(...) 13 | #endif 14 | 15 | #define ar array 16 | #define ll long long 17 | #define ld long double 18 | #define sza(x) ((int)x.size()) 19 | #define all(a) (a).begin(), (a).end() 20 | 21 | const int MAX_N = 1e5 + 5; 22 | const ll MOD = 1e9 + 7; 23 | const ll INF = 1e9; 24 | const ld EPS = 1e-9; 25 | 26 | 27 | 28 | void solve() { 29 | 30 | } 31 | 32 | int main() { 33 | ios_base::sync_with_stdio(0); 34 | cin.tie(0); cout.tie(0); 35 | int tc = 1; 36 | // cin >> tc; 37 | for (int t = 1; t <= tc; t++) { 38 | // cout << "Case #" << t << ": "; 39 | solve(); 40 | } 41 | } -------------------------------------------------------------------------------- /Data Structures/DSU.cpp: -------------------------------------------------------------------------------- 1 | // Disjoint Set Union 2 | // Union by rank & Path compression 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, par[MAX_N], sz[MAX_N], num_grp; 17 | 18 | int find(int u) { 19 | return u == par[u] ? u : par[u] = find(par[u]); 20 | } 21 | 22 | void merge(int u, int v) { 23 | u = find(u), v = find(v); 24 | if (u == v) return; 25 | if (sz[u] > sz[v]) swap(u, v); 26 | par[u] = v; 27 | sz[v] += sz[u]; 28 | num_grp--; 29 | } 30 | 31 | void solve() { 32 | cin >> n; 33 | num_grp = n; 34 | for (int i = 1; i <= n; i++) par[i] = i, sz[i] = 1; 35 | } 36 | 37 | int main() { 38 | ios_base::sync_with_stdio(0); 39 | cin.tie(0); cout.tie(0); 40 | // freopen("input.txt", "r", stdin); 41 | // freopen("output.txt", "w", stdout); 42 | 43 | int tc; tc = 1; 44 | for (int t = 1; t <= tc; t++) { 45 | // cout << "Case #" << t << ": "; 46 | solve(); 47 | } 48 | } -------------------------------------------------------------------------------- /Data Structures/Fenwick Tree/2D Fenwick Tree.cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://cses.fi/problemset/task/1739 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 1e3 + 1; 11 | const int MOD = 1e9 + 7; 12 | const int INF = 1e9; 13 | const ll LINF = 1e18; 14 | 15 | #define LSOne(S) ((S) & (-S)) 16 | 17 | int n, q, ft[MAX_N][MAX_N]; 18 | char grid[MAX_N][MAX_N]; 19 | 20 | void update(int x, int y, int v) { 21 | for (int tx = x; tx <= n; tx += LSOne(tx)) 22 | for (int ty = y; ty <= n; ty += LSOne(ty)) 23 | ft[tx][ty] += v; 24 | } 25 | 26 | int sum(int x, int y) { 27 | int res = 0; 28 | for (int tx = x; tx; tx -= LSOne(tx)) 29 | for (int ty = y; ty; ty -= LSOne(ty)) 30 | res += ft[tx][ty]; 31 | return res; 32 | } 33 | 34 | int query(int x1, int y1, int x2, int y2) { 35 | return sum(x2, y2) - sum(x1 - 1, y2) - sum(x2, y1 - 1) + sum(x1 - 1, y1 - 1); 36 | } 37 | 38 | void solve() { 39 | cin >> n >> q; 40 | for (int i = 1; i <= n; i++) { 41 | for (int j = 1; j <= n; j++) { 42 | cin >> grid[i][j]; 43 | if (grid[i][j] == '*') update(i, j, 1); 44 | } 45 | } 46 | while (q--) { 47 | char c; cin >> c; 48 | if (c == '1') { 49 | int x, y; cin >> x >> y; 50 | if (grid[x][y] == '*') { 51 | update(x, y, -1); 52 | grid[x][y] = '.'; 53 | } 54 | else { 55 | update(x, y, 1); 56 | grid[x][y] = '*'; 57 | } 58 | } 59 | else { 60 | int x1, x2, y1, y2; cin >> x1 >> y1 >> x2 >> y2; 61 | cout << query(x1, y1, x2, y2) << "\n"; 62 | } 63 | } 64 | } 65 | 66 | int main() { 67 | ios_base::sync_with_stdio(0); 68 | cin.tie(0); cout.tie(0); 69 | // freopen("input.txt", "r", stdin); 70 | // freopen("output.txt", "w", stdout); 71 | 72 | int tc; tc = 1; 73 | for (int t = 1; t <= tc; t++) { 74 | // cout << "Case #" << t << ": "; 75 | solve(); 76 | } 77 | } -------------------------------------------------------------------------------- /Data Structures/Fenwick Tree/Fenwick Tree (order statistic tree).cpp: -------------------------------------------------------------------------------- 1 | // Create something similar to PBDS using Fenwick Tree 2 | // Time complexity: O(logn) for both operations 3 | // Problem link: https://cses.fi/problemset/task/1144 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 2e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | const int MAX_L = 18; 18 | 19 | #define LSOne(S) ((S) & (-S)) 20 | 21 | int n, q, ft[MAX_N]; 22 | 23 | void update(int x, int v) { 24 | for (; x <= n; x += LSOne(x)) 25 | ft[x] += v; 26 | } 27 | 28 | int sum(int x) { 29 | int res = 0; 30 | for (; x; x -= LSOne(x)) 31 | res += ft[x]; 32 | return res; 33 | } 34 | 35 | // using binary lifting technique 36 | int find_by_order(int k) { 37 | int sum = 0, pos = 0; 38 | for (int i = MAX_L; i >= 0; i--) { 39 | if (pos + (1 << i) < n && sum + ft[pos + (1 << i)] < k) { 40 | sum += ft[pos + (1 << i)]; 41 | pos += (1 << i); 42 | } 43 | } 44 | return pos + 1; 45 | // +1 because 'pos' will have position of largest value less than 'k' 46 | // this function returns 1 if k < 1 and returns N if k > N 47 | } 48 | 49 | int order_of_key(int k) { 50 | return sum(k); 51 | } 52 | 53 | void solve() { 54 | cin >> n >> q; 55 | int arr[n]; 56 | for (int i = 0; i < n; i++) { 57 | cin >> arr[i]; 58 | update(arr[i], 1); 59 | } 60 | while (q--) { 61 | char c; cin >> c; 62 | if (c == '!') { 63 | int k, x; cin >> k >> x; k--; 64 | update(find_by_order(order_of_key(arr[k])), -1); 65 | update(x, 1); 66 | arr[k] = x; 67 | } 68 | else { 69 | int a, b; cin >> a >> b; 70 | cout << order_of_key(b + 1) - order_of_key(a) << "\n"; 71 | } 72 | } 73 | } 74 | 75 | int main() { 76 | ios_base::sync_with_stdio(0); 77 | cin.tie(0); cout.tie(0); 78 | // freopen("input.txt", "r", stdin); 79 | // freopen("output.txt", "w", stdout); 80 | 81 | int tc; tc = 1; 82 | for (int t = 1; t <= tc; t++) { 83 | // cout << "Case #" << t << ": "; 84 | solve(); 85 | } 86 | } -------------------------------------------------------------------------------- /Data Structures/Fenwick Tree/Fenwick Tree (point update, range query).cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://cses.fi/problemset/task/1648 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 2e5 + 1; 11 | const int MOD = 1e9 + 7; 12 | const int INF = 1e9; 13 | const ll LINF = 1e18; 14 | 15 | #define LSOne(S) ((S) & (-S)) 16 | 17 | int n, q; 18 | ll ft[MAX_N]; 19 | 20 | void update(int x, int v) { 21 | for (; x <= n; x += LSOne(x)) 22 | ft[x] += v; 23 | } 24 | 25 | ll sum(int x) { 26 | ll res = 0; 27 | for (; x; x -= LSOne(x)) 28 | res += ft[x]; 29 | return res; 30 | } 31 | 32 | ll rsq(int l, int r) { 33 | return sum(r) - sum(l - 1); 34 | } 35 | 36 | void solve() { 37 | cin >> n >> q; 38 | for (int i = 1; i <= n; i++) { 39 | int x; cin >> x; 40 | update(i, x); 41 | } 42 | while (q--) { 43 | int t; cin >> t; 44 | if (t == 1) { 45 | int x, v; cin >> x >> v; 46 | update(x, v - rsq(x, x)); 47 | } 48 | else { 49 | int l, r; cin >> l >> r; 50 | cout << rsq(l, r) << "\n"; 51 | } 52 | } 53 | } 54 | 55 | int main() { 56 | ios_base::sync_with_stdio(0); 57 | cin.tie(0); cout.tie(0); 58 | // freopen("input.txt", "r", stdin); 59 | // freopen("output.txt", "w", stdout); 60 | 61 | int tc; tc = 1; 62 | for (int t = 1; t <= tc; t++) { 63 | // cout << "Case #" << t << ": "; 64 | solve(); 65 | } 66 | } -------------------------------------------------------------------------------- /Data Structures/Fenwick Tree/Fenwick Tree (range update, point query).cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://cses.fi/problemset/task/1651 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 2e5 + 1; 11 | const int MOD = 1e9 + 7; 12 | const int INF = 1e9; 13 | const ll LINF = 1e18; 14 | 15 | #define LSOne(S) ((S) & (-S)) 16 | 17 | int n, q; 18 | ll ft[MAX_N]; 19 | 20 | void update(int x, int v) { 21 | for (; x <= n; x += LSOne(x)) 22 | ft[x] += v; 23 | } 24 | 25 | void range_update(int l, int r, int v) { 26 | update(l, v); 27 | update(r + 1, -v); 28 | } 29 | 30 | ll sum(int x) { 31 | ll res = 0; 32 | for (; x; x -= LSOne(x)) 33 | res += ft[x]; 34 | return res; 35 | } 36 | 37 | void solve() { 38 | cin >> n >> q; 39 | for (int i = 1; i <= n; i++) { 40 | int x; cin >> x; 41 | range_update(i, i, x); 42 | } 43 | while (q--) { 44 | int t; cin >> t; 45 | if (t == 1) { 46 | int l, r, v; cin >> l >> r >> v; 47 | range_update(l, r, v); 48 | } 49 | else { 50 | int x; cin >> x; 51 | cout << sum(x) << "\n"; 52 | } 53 | } 54 | } 55 | 56 | int main() { 57 | ios_base::sync_with_stdio(0); 58 | cin.tie(0); cout.tie(0); 59 | // freopen("input.txt", "r", stdin); 60 | // freopen("output.txt", "w", stdout); 61 | 62 | int tc; tc = 1; 63 | for (int t = 1; t <= tc; t++) { 64 | // cout << "Case #" << t << ": "; 65 | solve(); 66 | } 67 | } -------------------------------------------------------------------------------- /Data Structures/Fenwick Tree/Fenwick Tree (range update, range query).cpp: -------------------------------------------------------------------------------- 1 | // Use 2 fenwick trees to support both range updates and range queries (RURQ) 2 | // A combination of PURQ and RUPQ 3 | // Problem link: https://www.spoj.com/problems/HORRIBLE/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | #define LSOne(S) ((S) & (-S)) 18 | 19 | int n, q; 20 | ll ft1[MAX_N], ft2[MAX_N]; 21 | 22 | void update(ll *ft, int x, ll v) { 23 | for (; x <= n; x += LSOne(x)) 24 | ft[x] += v; 25 | } 26 | 27 | void range_update(int l, int r, ll v) { 28 | update(ft1, l, v); 29 | update(ft1, r + 1, -v); 30 | update(ft2, l, v * (l - 1)); 31 | update(ft2, r + 1, -v * r); 32 | } 33 | 34 | ll sum(ll *ft, int x) { 35 | ll res = 0; 36 | for (; x; x -= LSOne(x)) 37 | res += ft[x]; 38 | return res; 39 | } 40 | 41 | // sum of all elements in [1...x] 42 | ll ps(int x) { 43 | return sum(ft1, x) * x - sum(ft2, x); 44 | } 45 | 46 | ll rsq(int l, int r) { 47 | return ps(r) - ps(l - 1); 48 | } 49 | 50 | void solve() { 51 | memset(ft1, 0, sizeof ft1); 52 | memset(ft2, 0, sizeof ft2); 53 | cin >> n >> q; 54 | while (q--) { 55 | int t, l, r; cin >> t >> l >> r; 56 | if (t == 0) { 57 | int v; cin >> v; 58 | range_update(l, r, v); 59 | } 60 | else { 61 | cout << rsq(l, r) << "\n"; 62 | } 63 | } 64 | } 65 | 66 | int main() { 67 | ios_base::sync_with_stdio(0); 68 | cin.tie(0); cout.tie(0); 69 | // freopen("input.txt", "r", stdin); 70 | // freopen("output.txt", "w", stdout); 71 | 72 | int tc; cin >> tc; 73 | for (int t = 1; t <= tc; t++) { 74 | // cout << "Case #" << t << ": "; 75 | solve(); 76 | } 77 | } -------------------------------------------------------------------------------- /Data Structures/HLD.cpp: -------------------------------------------------------------------------------- 1 | // Heavy-light decomposition (HLD) is a data structure to answer queries and update values on tree 2 | // Splitting the trees into separate paths that allows us to use another data structure such as segment tree on a tree 3 | // As we decompose the tree, we have enough information to build a lca function (which will be useful as an intermediate step for many types of queries) 4 | // For this example, we will answer maximum edge cost query on the path between two nodes 5 | // Problem link: https://www.spoj.com/problems/QTREE/ 6 | 7 | // Each edge is represented by the node that is further away to the root 8 | // => Each node is associated only one unique edge, except the root node 9 | 10 | // sz[u] = size of the subtree of u 11 | // par[u] = parent node of u 12 | // dep[u] = distance of u from the root 13 | 14 | // chainNum = number of decomposed chains 15 | // chainSize[s] = number of nodes in chain s 16 | // chainHead[s] = the node closest to the root in chain s 17 | // chainId[u] = the chain that node u belongs to 18 | // chainPos[u] = the position of node u in the chain it belongs to (aka chainInd[u]) 19 | 20 | // adj: adjacency list 21 | // el: edge list 22 | 23 | // arr: array storing edge costs based on HLD 24 | // pos: position of edges based on HLD 25 | // st: segment tree 26 | 27 | #include 28 | 29 | using namespace std; 30 | 31 | #define ar array 32 | #define ll long long 33 | 34 | const int MAX_N = 1e4 + 1; 35 | const int MOD = 1e9 + 7; 36 | const int INF = 1e9; 37 | const ll LINF = 1e18; 38 | 39 | struct segtree { 40 | struct tdata { 41 | ll mx; 42 | tdata(): mx() {} 43 | tdata(ll val): mx(val) {} 44 | tdata(tdata l, tdata r): mx(max(l.mx, r.mx)) {} 45 | }; 46 | int ln(int node) {return 2 * node;} 47 | int rn(int node) {return 2 * node + 1;} 48 | int n; vector st; 49 | void init(int _n) { 50 | n = _n; 51 | st.resize(4 * n); 52 | } 53 | void init(vector &arr) { 54 | n = arr.size(); 55 | st.resize(4 * n); 56 | build(arr, 1, 0, n - 1); 57 | } 58 | void apply(int node, ll val) { 59 | st[node].mx = val; 60 | } 61 | void combine(int node) { 62 | st[node].mx = max(st[ln(node)].mx, st[rn(node)].mx); 63 | } 64 | void build(vector &arr, int node, int start, int end) { 65 | if (start == end) { 66 | st[node] = tdata(arr[start]); 67 | return; 68 | } 69 | int mid = (start + end) / 2; 70 | build(arr, ln(node), start, mid); 71 | build(arr, rn(node), mid + 1, end); 72 | combine(node); 73 | } 74 | void update(int node, int start, int end, int idx, ll val) { 75 | if (start == end) { 76 | apply(node, val); 77 | return; 78 | } 79 | int mid = (start + end) / 2; 80 | if (idx <= mid) update(ln(node), start, mid, idx, val); 81 | else update(rn(node), mid + 1, end, idx, val); 82 | combine(node); 83 | } 84 | tdata query(int node, int start, int end, int l, int r) { 85 | if (r < start || end < l) return tdata(); 86 | if (l <= start && end <= r) return st[node]; 87 | int mid = (start + end) / 2; 88 | return tdata(query(ln(node), start, mid, l, r), query(rn(node), mid + 1, end, l, r)); 89 | } 90 | void update(int idx, ll val) {update(1, 0, n - 1, idx, val);} 91 | tdata query(int l, int r) {return query(1, 0, n - 1, l, r);} 92 | }; 93 | 94 | int n, cnt; 95 | int sz[MAX_N], dep[MAX_N], par[MAX_N], child[MAX_N]; 96 | int chainNum, chainHead[MAX_N], chainSize[MAX_N], chainId[MAX_N], chainPos[MAX_N]; 97 | vector arr; int pos[MAX_N]; 98 | vector> adj[MAX_N], el; 99 | segtree st; 100 | 101 | void reset() { 102 | memset(chainHead, -1, sizeof chainHead); 103 | arr.clear(); 104 | for (int i = 1; i <= n; i++) adj[i].clear(); 105 | el.clear(); 106 | chainNum = cnt = 0; 107 | } 108 | 109 | void dfs(int u, int p = 0, int d = 0) { 110 | sz[u] = 1; 111 | dep[u] = d; 112 | par[u] = p; 113 | int mx = 0; 114 | for (auto [v, w] : adj[u]) { 115 | if (v != p) { 116 | dfs(v, u, d + 1); 117 | sz[u] += sz[v]; 118 | if (sz[v] > mx) mx = sz[v], child[u] = v; 119 | } 120 | } 121 | } 122 | 123 | void hld(int u, int x = -INF) { 124 | if (chainHead[chainNum] == -1) chainHead[chainNum] = u; 125 | chainId[u] = chainNum; 126 | chainPos[u] = chainSize[chainNum]++; 127 | arr.push_back(x); 128 | pos[u] = cnt++; 129 | for (auto [v, w] : adj[u]) { 130 | if (v != par[u] && v == child[u]) { 131 | hld(v, w); 132 | } 133 | } 134 | for (auto [v, w] : adj[u]) { 135 | if (v != par[u] && v != child[u]) { 136 | chainNum++, hld(v, w); 137 | } 138 | } 139 | } 140 | 141 | int lca(int u, int v) { 142 | while (chainId[u] != chainId[v]) { 143 | if (dep[chainHead[chainId[u]]] > dep[chainHead[chainId[v]]]) u = par[chainHead[chainId[u]]]; 144 | else v = par[chainHead[chainId[v]]]; 145 | } 146 | return dep[u] > dep[v] ? v : u; 147 | } 148 | 149 | ll query_up(int u, int m) { 150 | ll res = 0; 151 | while (true) { 152 | if (u == m) break; 153 | if (chainId[u] == chainId[m]) { 154 | res = max(res, st.query(pos[m] + 1, pos[u]).mx); 155 | break; 156 | } 157 | res = max(res, st.query(pos[chainHead[chainId[u]]], pos[u]).mx); 158 | u = par[chainHead[chainId[u]]]; 159 | } 160 | return res; 161 | } 162 | 163 | ll query(int u, int v) { 164 | int m = lca(u, v); 165 | return max(query_up(u, m), query_up(v, m)); 166 | } 167 | 168 | void update(int i, int x) { 169 | auto [u, v] = el[i]; 170 | if (dep[u] < dep[v]) swap(u, v); 171 | st.update(pos[u], x); 172 | } 173 | 174 | void solve() { 175 | cin >> n; 176 | reset(); 177 | for (int i = 0; i < n - 1; i++) { 178 | int u, v, w; cin >> u >> v >> w; 179 | adj[u].push_back({v, w}); 180 | adj[v].push_back({u, w}); 181 | el.push_back({u, v}); 182 | } 183 | dfs(1); 184 | hld(1); 185 | st.init(arr); 186 | while (true) { 187 | string t; cin >> t; 188 | if (t == "CHANGE") { 189 | int i, x; cin >> i >> x; i--; 190 | update(i, x); 191 | } 192 | else if (t == "QUERY") { 193 | int u, v; cin >> u >> v; 194 | cout << query(u, v) << "\n"; 195 | } 196 | else return; 197 | } 198 | } 199 | 200 | int main() { 201 | ios_base::sync_with_stdio(0); 202 | cin.tie(0); cout.tie(0); 203 | // freopen("input.txt", "r", stdin); 204 | // freopen("output.txt", "w", stdout); 205 | 206 | int tc; cin >> tc; 207 | for (int t = 1; t <= tc; t++) { 208 | // cout << "Case #" << t << ": "; 209 | solve(); 210 | } 211 | } -------------------------------------------------------------------------------- /Data Structures/PBDS.cpp: -------------------------------------------------------------------------------- 1 | // Policy based data structures C++ STL 2 | // order_of_key(k): number of elements less than k 3 | // find_by_order(k): returns the iterator of the k-th element in a set (0-index) 4 | // Time complexity: O(logn) for both 5 | // Problem link: https://cses.fi/problemset/task/1144 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | #define ar array 12 | #define ll long long 13 | 14 | const int MAX_N = 1e5 + 1; 15 | const int MOD = 1e9 + 7; 16 | const int INF = 1e9; 17 | const ll LINF = 1e18; 18 | 19 | // 5 lines 20 | #include 21 | #include 22 | using namespace __gnu_pbds; 23 | template using ordered_set = tree, rb_tree_tag, tree_order_statistics_node_update>; 24 | template using ordered_map = tree, rb_tree_tag, tree_order_statistics_node_update>; 25 | 26 | void solve() { 27 | int n, q; cin >> n >> q; 28 | int arr[n]; 29 | ordered_set> os; 30 | for (int i = 0; i < n; i++) { 31 | cin >> arr[i]; 32 | os.insert({arr[i], i}); 33 | } 34 | while (q--) { 35 | char c; cin >> c; 36 | if (c == '!') { 37 | int k, x; cin >> k >> x; k--; 38 | os.erase(os.find_by_order(os.order_of_key({arr[k], k}))); 39 | os.insert({x, k}); 40 | arr[k] = x; 41 | } 42 | else { 43 | int a, b; cin >> a >> b; 44 | cout << os.order_of_key({b + 1, 0}) - os.order_of_key({a, 0}) << "\n"; 45 | } 46 | } 47 | } 48 | 49 | int main() { 50 | ios_base::sync_with_stdio(0); 51 | cin.tie(0); cout.tie(0); 52 | // freopen("input.txt", "r", stdin); 53 | // freopen("output.txt", "w", stdout); 54 | 55 | int tc; tc = 1; 56 | for (int t = 1; t <= tc; t++) { 57 | // cout << "Case #" << t << ": "; 58 | solve(); 59 | } 60 | } -------------------------------------------------------------------------------- /Data Structures/SQRT.cpp: -------------------------------------------------------------------------------- 1 | // Mo's Algorithm for answering offline queries 2 | // Time complexity: O(n*sqrt(n)) 3 | // Problem link: https://cses.fi/problemset/task/1734 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 2e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | struct query{ 18 | int SQRT = 500; 19 | int l, r, id; 20 | bool operator< (query b) { 21 | query a = *this; 22 | return ar{a.l/SQRT, a.r} < ar{b.l/SQRT, b.r}; 23 | } 24 | }; 25 | 26 | int n, q, arr[MAX_N], ans[MAX_N], cnt[MAX_N], cur; 27 | query qs[MAX_N]; 28 | 29 | void add(int idx) { 30 | if (cnt[arr[idx]] == 0) cur++; 31 | cnt[arr[idx]]++; 32 | } 33 | 34 | void subtract(int idx) { 35 | if (cnt[arr[idx]] == 1) cur--; 36 | cnt[arr[idx]]--; 37 | } 38 | 39 | // compress used values from 1e9 to 2e5 40 | void compress() { 41 | map mp; 42 | for (int i = 1; i <= n; i++) 43 | mp[arr[i]] = i; 44 | for (int i = 1; i <= n; i++) 45 | arr[i] = mp[arr[i]]; 46 | } 47 | 48 | void mo_algo() { 49 | sort(qs + 1, qs + n + 1); 50 | int curL = 0, curR = 0; 51 | add(0); 52 | for (int i = 1; i <= n; i++) { 53 | int L = qs[i].l, R = qs[i].r; 54 | while (curL < L) subtract(curL++); 55 | while (curL > L) add(--curL); 56 | while (curR < R) add(++curR); 57 | while (curR > R) subtract(curR--); 58 | ans[qs[i].id] = cur; 59 | } 60 | } 61 | 62 | void solve() { 63 | cin >> n >> q; 64 | for (int i = 1; i <= n; i++) cin >> arr[i]; 65 | compress(); 66 | for (int i = 1; i <= q; i++) { 67 | cin >> qs[i].l >> qs[i].r; 68 | qs[i].id = i; 69 | } 70 | mo_algo(); 71 | for (int i = 1; i <= q; i++) 72 | cout << ans[i] << "\n"; 73 | } 74 | 75 | int main() { 76 | ios_base::sync_with_stdio(0); 77 | cin.tie(0); cout.tie(0); 78 | // freopen("input.txt", "r", stdin); 79 | // freopen("output.txt", "w", stdout); 80 | 81 | int tc; tc = 1; 82 | for (int t = 1; t <= tc; t++) { 83 | // cout << "Case #" << t << ": "; 84 | solve(); 85 | } 86 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Advanced example 1.cpp: -------------------------------------------------------------------------------- 1 | // Segment tree for subarray sum query 2 | // Problem link: https://cses.fi/problemset/task/1190 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | struct tdata { 17 | ll sum, pref, suff, ans; 18 | tdata() { 19 | sum = pref = suff = ans = 0; 20 | } 21 | tdata(int val) { 22 | sum = val; 23 | pref = suff = ans = max(0, val); 24 | } 25 | tdata(tdata l, tdata r) { 26 | sum = l.sum + r.sum; 27 | pref = max(l.pref, l.sum + r.pref); 28 | suff = max(r.suff, r.sum + l.suff); 29 | ans = max({l.ans, r.ans, l.suff + r.pref}); 30 | } 31 | }; 32 | 33 | int n, q, arr[MAX_N]; 34 | tdata st[4 * MAX_N]; 35 | 36 | void build(int node, int start, int end) { 37 | if (start == end) { 38 | st[node] = tdata(arr[start]); 39 | return; 40 | } 41 | int mid = (start + end) / 2; 42 | build(2 * node, start, mid); 43 | build(2 * node + 1, mid + 1, end); 44 | st[node] = tdata(st[2 * node], st[2 * node + 1]); 45 | } 46 | 47 | void update(int node, int start, int end, int idx, int val) { 48 | if (start == end) { 49 | arr[idx] = val; 50 | st[node] = tdata(val); 51 | return; 52 | } 53 | int mid = (start + end) / 2; 54 | if (idx <= mid) update(2 * node, start, mid, idx, val); 55 | else update(2 * node + 1, mid + 1, end, idx, val); 56 | st[node] = tdata(st[2 * node], st[2 * node + 1]); 57 | } 58 | 59 | tdata query(int node, int start, int end, int l, int r) { 60 | if (start > r || end < l) return tdata(0); 61 | if (l <= start && end <= r) return st[node]; 62 | int mid = (start + end) / 2; 63 | return tdata(query(2 * node, start, mid, l, r), query(2 * node + 1, mid + 1, end, l, r)); 64 | } 65 | 66 | void solve() { 67 | cin >> n >> q; 68 | for (int i = 1; i <= n; i++) cin >> arr[i]; 69 | build(1, 1, n); 70 | while (q--) { 71 | int k, x; cin >> k >> x; 72 | update(1, 1, n, k, x); 73 | cout << query(1, 1, n, 1, n).ans << "\n"; 74 | // this is the same as 75 | // cout << st[1].ans << "\n"; 76 | } 77 | } 78 | 79 | int main() { 80 | ios_base::sync_with_stdio(0); 81 | cin.tie(0); cout.tie(0); 82 | // freopen("input.txt", "r", stdin); 83 | // freopen("output.txt", "w", stdout); 84 | 85 | int tc; tc = 1; 86 | for (int t = 1; t <= tc; t++) { 87 | // cout << "Case #" << t << ": "; 88 | solve(); 89 | } 90 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Advanced example 2.cpp: -------------------------------------------------------------------------------- 1 | // Descending on segment tree 2 | // Problem link: https://cses.fi/problemset/task/1143/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, q; 17 | int arr[MAX_N], st[4 * MAX_N]; 18 | 19 | void build(int node, int start, int end) { 20 | if (start == end) 21 | st[node] = arr[start]; 22 | else { 23 | int mid = (start + end) / 2; 24 | build(2 * node, start, mid); 25 | build(2 * node + 1, mid + 1, end); 26 | st[node] = max(st[2 * node], st[2 * node + 1]); 27 | } 28 | } 29 | 30 | void update(int node, int start, int end, int idx, int val) { 31 | if (start == end) { 32 | arr[idx] += val; 33 | st[node] += val; 34 | } 35 | else { 36 | int mid = (start + end) / 2; 37 | if (idx <= mid) update(2 * node, start, mid, idx, val); 38 | else update(2 * node + 1, mid + 1, end, idx, val); 39 | st[node] = max(st[2 * node], st[2 * node + 1]); 40 | } 41 | } 42 | 43 | int query(int node, int start, int end, int val) { 44 | if (start == end) return (st[node] >= val) ? start : 0; 45 | int mid = (start + end) / 2; 46 | if (st[2 * node] >= val) 47 | return query(2 * node, start, mid, val); 48 | else 49 | return query(2 * node + 1, mid + 1, end, val); 50 | } 51 | 52 | void solve() { 53 | cin >> n >> q; 54 | for (int i = 1; i <= n; i++) cin >> arr[i]; 55 | build(1, 1, n); 56 | while (q--) { 57 | int val; cin >> val; 58 | int idx = query(1, 1, n, val); 59 | cout << idx << " "; 60 | if (idx) update(1, 1, n, idx, -val); 61 | } 62 | } 63 | 64 | int main() { 65 | ios_base::sync_with_stdio(0); 66 | cin.tie(0); cout.tie(0); 67 | // freopen("input.txt", "r", stdin); 68 | // freopen("output.txt", "w", stdout); 69 | 70 | int tc; tc = 1; 71 | for (int t = 1; t <= tc; t++) { 72 | // cout << "Case #" << t << ": "; 73 | solve(); 74 | } 75 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Advanced example 3.cpp: -------------------------------------------------------------------------------- 1 | // Segment tree with lazy propagation for range set bit count query, range toggle update 2 | // Problem link: https://www.spoj.com/problems/LITE/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | struct tdata { 17 | int cnt, lz; 18 | tdata() { 19 | cnt = lz = 0; 20 | } 21 | }; 22 | 23 | int n, q, arr[MAX_N]; 24 | tdata st[4 * MAX_N]; 25 | 26 | void down(int node, int start, int end) { 27 | if (st[node].lz) { 28 | st[node].cnt = (end - start + 1) - st[node].cnt; 29 | if (start != end) { 30 | st[2 * node].lz = !st[2 * node].lz; 31 | st[2 * node + 1].lz = !st[2 * node + 1].lz; 32 | } 33 | st[node].lz = 0; 34 | } 35 | } 36 | 37 | void update(int node, int start, int end, int l, int r) { 38 | down(node, start, end); 39 | if (r < start || end < l) return; 40 | if (l <= start && end <= r) { 41 | st[node].cnt = (end - start + 1) - st[node].cnt; 42 | if (start != end) { 43 | st[2 * node].lz = !st[2 * node].lz; 44 | st[2 * node + 1].lz = !st[2 * node + 1].lz; 45 | } 46 | return; 47 | } 48 | int mid = (start + end) / 2; 49 | update(2 * node, start, mid, l, r); 50 | update(2 * node + 1, mid + 1, end, l, r); 51 | st[node].cnt = st[2 * node].cnt + st[2 * node + 1].cnt; 52 | } 53 | 54 | 55 | int query(int node, int start, int end, int l, int r) { 56 | down(node, start, end); 57 | if (r < start || end < l) return 0; 58 | if (l <= start && end <= r) return st[node].cnt; 59 | int mid = (start + end) / 2; 60 | return query(2 * node, start, mid, l, r) + query(2 * node + 1, mid + 1, end, l, r); 61 | } 62 | 63 | void solve() { 64 | cin >> n >> q; 65 | while (q--) { 66 | int t, l, r; cin >> t >> l >> r; 67 | if (t == 0) update(1, 1, n, l, r); 68 | else cout << query(1, 1, n, l, r) << "\n"; 69 | } 70 | } 71 | 72 | int main() { 73 | ios_base::sync_with_stdio(0); 74 | cin.tie(0); cout.tie(0); 75 | // freopen("input.txt", "r", stdin); 76 | // freopen("output.txt", "w", stdout); 77 | 78 | int tc; tc = 1; 79 | for (int t = 1; t <= tc; t++) { 80 | // cout << "Case #" << t << ": "; 81 | solve(); 82 | } 83 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Segment Tree (Lazy Propagation).cpp: -------------------------------------------------------------------------------- 1 | // Segment tree with lazy propagation for range sum query, range add update, range set update 2 | // Problem link: https://cses.fi/problemset/task/1735/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | struct tdata { 17 | ll sum, setval, addval; 18 | bool lazyset; 19 | tdata() { 20 | sum = setval = addval = lazyset = 0; 21 | } 22 | tdata(ll val) { 23 | sum = val; 24 | setval = addval = lazyset = 0; 25 | } 26 | tdata(tdata l, tdata r) { 27 | sum = l.sum + r.sum; 28 | } 29 | }; 30 | 31 | int n, q, arr[MAX_N]; 32 | tdata st[4 * MAX_N]; 33 | 34 | void build(int node, int start, int end) { 35 | if (start == end) { 36 | st[node] = tdata(arr[start]); 37 | return; 38 | } 39 | int mid = (start + end) / 2; 40 | build(2 * node, start, mid); 41 | build(2 * node + 1, mid + 1, end); 42 | st[node].sum = st[2 * node].sum + st[2 * node + 1].sum; 43 | } 44 | 45 | void down(int node, int start, int end) { 46 | int mid = (start + end) / 2; 47 | if (st[node].lazyset) { 48 | st[2 * node] = st[2 * node + 1] = st[node]; 49 | st[2 * node].sum = (st[node].setval + st[node].addval) * (mid - start + 1); 50 | st[2 * node + 1].sum = (st[node].setval + st[node].addval) * (end - mid); 51 | } 52 | else { 53 | st[2 * node].addval += st[node].addval; 54 | st[2 * node + 1].addval += st[node].addval; 55 | st[2 * node].sum += st[node].addval * (mid - start + 1); 56 | st[2 * node + 1].sum += st[node].addval * (end - mid); 57 | } 58 | st[node].addval = st[node].setval = st[node].lazyset = 0; 59 | } 60 | 61 | // t = 1 means range add update, t = 2 means range set update 62 | void update(int node, int start, int end, int l, int r, ll val, int t) { 63 | if (r < start || end < l) return; 64 | if (l <= start && end <= r) { 65 | if (t == 2) { 66 | st[node].setval = val; 67 | st[node].lazyset = 1; 68 | st[node].addval = 0; 69 | st[node].sum = val * (end - start + 1); 70 | } 71 | else { 72 | st[node].addval += val; 73 | st[node].sum += val * (end - start + 1); 74 | } 75 | return; 76 | } 77 | down(node, start, end); 78 | int mid = (start + end) / 2; 79 | update(2 * node, start, mid, l, r, val, t); 80 | update(2 * node + 1, mid + 1, end, l, r, val, t); 81 | st[node].sum = st[2 * node].sum + st[2 * node + 1].sum; 82 | } 83 | 84 | tdata query(int node, int start, int end, int l, int r) { 85 | if (r < start || end < l) return tdata(0); 86 | if (l <= start && end <= r) return st[node]; 87 | down(node, start, end); 88 | int mid = (start + end) / 2; 89 | return tdata(query(2 * node, start, mid, l, r), query(2 * node + 1, mid + 1, end, l, r)); 90 | } 91 | 92 | void solve() { 93 | cin >> n >> q; 94 | for (int i = 1; i <= n; i++) cin >> arr[i]; 95 | build(1, 1, n); 96 | while (q--) { 97 | int t, l, r; cin >> t >> l >> r; 98 | if (t == 3) cout << query(1, 1, n, l, r).sum << "\n"; 99 | else { 100 | int x; cin >> x; 101 | update(1, 1, n, l, r, x, t); 102 | } 103 | } 104 | } 105 | 106 | int main() { 107 | ios_base::sync_with_stdio(0); 108 | cin.tie(0); cout.tie(0); 109 | // freopen("input.txt", "r", stdin); 110 | // freopen("output.txt", "w", stdout); 111 | 112 | int tc; tc = 1; 113 | for (int t = 1; t <= tc; t++) { 114 | // cout << "Case #" << t << ": "; 115 | solve(); 116 | } 117 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Segment Tree (Persistent).cpp: -------------------------------------------------------------------------------- 1 | // Persistent segment tree for range sum query, point set update 2 | // Here implement with pointers 3 | // Problem link: https://cses.fi/problemset/task/1737 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 2e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | struct tdata { 18 | tdata *l, *r; 19 | ll sum; 20 | tdata() {} 21 | tdata(tdata* l, tdata* r, int val) : l(l), r(r), sum(val) {} 22 | }; 23 | 24 | int n, q, cnt, arr[MAX_N]; 25 | tdata *ver[MAX_N]; 26 | 27 | void build(tdata *node, int start, int end) { 28 | if (start == end) { 29 | node->sum = arr[start]; 30 | return; 31 | } 32 | node->l = new tdata(); node->r = new tdata(); 33 | int mid = (start + end) / 2; 34 | build(node->l, start, mid); 35 | build(node->r, mid + 1, end); 36 | node->sum = node->l->sum + node->r->sum; 37 | } 38 | 39 | void update(tdata *node, int start, int end, int idx, int val) { 40 | if (start == end) { 41 | node->sum = val; 42 | return; 43 | } 44 | int mid = (start + end) / 2; 45 | if (idx <= mid) { 46 | tdata *l = node->l; 47 | node->l = new tdata(l->l, l->r, l->sum); 48 | update(node->l, start, mid, idx, val); 49 | } 50 | else { 51 | tdata *r = node->r; 52 | node->r = new tdata(r->l, r->r, r->sum); 53 | update(node->r, mid + 1, end, idx, val); 54 | } 55 | node->sum = node->l->sum + node->r->sum; 56 | } 57 | 58 | ll query(tdata *node, int start, int end, int l, int r) { 59 | if (r < start || end < l) return 0; 60 | if (l <= start && end <= r) return node->sum; 61 | int mid = (start + end) / 2; 62 | return query(node->l, start, mid, l, r) + query(node->r, mid + 1, end, l, r); 63 | } 64 | 65 | void solve() { 66 | cin >> n >> q; 67 | for (int i = 1; i <= n; i++) cin >> arr[i]; 68 | ver[++cnt] = new tdata(); 69 | build(ver[cnt], 1, n); 70 | while (q--) { 71 | int t, k; cin >> t >> k; 72 | if (t == 1) { 73 | int a, x; cin >> a >> x; 74 | update(ver[k], 1, n, a, x); 75 | } 76 | else if (t == 2) { 77 | int a, b; cin >> a >> b; 78 | cout << query(ver[k], 1, n, a, b) << "\n"; 79 | } 80 | else { 81 | ver[++cnt] = new tdata(ver[k]->l, ver[k]->r, ver[k]->sum); 82 | } 83 | } 84 | } 85 | 86 | int main() { 87 | ios_base::sync_with_stdio(0); 88 | cin.tie(0); cout.tie(0); 89 | // freopen("input.txt", "r", stdin); 90 | // freopen("output.txt", "w", stdout); 91 | 92 | int tc; tc = 1; 93 | for (int t = 1; t <= tc; t++) { 94 | // cout << "Case #" << t << ": "; 95 | solve(); 96 | } 97 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Segment Tree (Recursive).cpp: -------------------------------------------------------------------------------- 1 | // Segment tree for range minimum query, point set update 2 | // Problem link: https://cses.fi/problemset/task/1649 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, q, arr[MAX_N], st[4 * MAX_N]; 17 | 18 | void build(int node, int start, int end) { 19 | if (start == end) { 20 | st[node] = arr[start]; 21 | return; 22 | } 23 | int mid = (start + end) / 2; 24 | build(2 * node, start, mid); 25 | build(2 * node + 1, mid + 1, end); 26 | st[node] = min(st[2 * node], st[2 * node + 1]); 27 | } 28 | 29 | void update(int node, int start, int end, int idx, int val) { 30 | if (start == end) { 31 | arr[idx] = val; 32 | st[node] = val; 33 | return; 34 | } 35 | int mid = (start + end) / 2; 36 | if (idx <= mid) update(2 * node, start, mid, idx, val); 37 | else update(2 * node + 1, mid + 1, end, idx, val); 38 | st[node] = min(st[2 * node], st[2 * node + 1]); 39 | } 40 | 41 | int query(int node, int start, int end, int l, int r) { 42 | if (start > r || end < l) return INF; 43 | if (l <= start && end <= r) return st[node]; 44 | int mid = (start + end) / 2; 45 | return min(query(2 * node, start, mid, l, r), query(2 * node + 1, mid + 1, end, l, r)); 46 | } 47 | 48 | void solve() { 49 | cin >> n >> q; 50 | for (int i = 1; i <= n; i++) cin >> arr[i]; 51 | build(1, 1, n); 52 | while (q--) { 53 | int t; cin >> t; 54 | if (t == 1) { 55 | int k, u; cin >> k >> u; 56 | update(1, 1, n, k, u); 57 | } 58 | else { 59 | int l, r; cin >> l >> r; 60 | cout << query(1, 1, n, l, r) << "\n"; 61 | } 62 | } 63 | } 64 | 65 | int main() { 66 | ios_base::sync_with_stdio(0); 67 | cin.tie(0); cout.tie(0); 68 | // freopen("input.txt", "r", stdin); 69 | // freopen("output.txt", "w", stdout); 70 | 71 | int tc; tc = 1; 72 | for (int t = 1; t <= tc; t++) { 73 | // cout << "Case #" << t << ": "; 74 | solve(); 75 | } 76 | } -------------------------------------------------------------------------------- /Data Structures/Segment Tree/Segment Tree Beats.cpp: -------------------------------------------------------------------------------- 1 | // Segment tree beats for chmax, chmin and add range updates 2 | // Problem link: https://judge.yosupo.jp/problem/range_chmin_chmax_add_range_sum 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | struct segtree { 17 | struct tdata { 18 | ll sum, addval, mx, mx2, mx_cnt, mn, mn2, mn_cnt; 19 | tdata(): sum(), addval(), mx(-LINF), mx2(-LINF), mx_cnt(), mn(LINF), mn2(LINF), mn_cnt() {} 20 | tdata(ll val): sum(val), addval(), mx(val), mx2(-LINF), mx_cnt(1), mn(val), mn2(LINF), mn_cnt(1) {} 21 | tdata(tdata l, tdata r) { 22 | sum = l.sum + r.sum; 23 | if (l.mx > r.mx) { 24 | mx = l.mx; 25 | mx2 = max(l.mx2, r.mx); 26 | mx_cnt = l.mx_cnt; 27 | } 28 | else if (r.mx > l.mx) { 29 | mx = r.mx; 30 | mx2 = max(r.mx2, l.mx); 31 | mx_cnt = r.mx_cnt; 32 | } 33 | else { 34 | mx = l.mx; 35 | mx2 = max(l.mx2, r.mx2); 36 | mx_cnt = l.mx_cnt + r.mx_cnt; 37 | } 38 | if (l.mn < r.mn) { 39 | mn = l.mn; 40 | mn2 = min(l.mn2, r.mn); 41 | mn_cnt = l.mn_cnt; 42 | } 43 | else if (r.mn < l.mn) { 44 | mn = r.mn; 45 | mn2 = min(r.mn2, l.mn); 46 | mn_cnt = r.mn_cnt; 47 | } 48 | else { 49 | mn = l.mn; 50 | mn2 = min(l.mn2, r.mn2); 51 | mn_cnt = l.mn_cnt + r.mn_cnt; 52 | } 53 | } 54 | }; 55 | int ln(int node) {return 2 * node;} 56 | int rn(int node) {return 2 * node + 1;} 57 | int n; vector st; 58 | segtree(int n): n(n), st(4 * n) {} 59 | segtree(vector &arr) : segtree(arr.size()) { 60 | build(arr, 1, 0, n - 1); 61 | } 62 | void apply_add(int node, int start, int end, ll val) { 63 | st[node].sum += val * (end - start + 1); 64 | st[node].mx += val; 65 | st[node].mn += val; 66 | if (st[node].mx2 != -LINF) st[node].mx2 += val; 67 | if (st[node].mn2 != LINF) st[node].mn2 += val; 68 | st[node].addval += val; 69 | } 70 | void apply_min(int node, ll val) { 71 | st[node].sum += (val - st[node].mx) * st[node].mx_cnt; 72 | st[node].mx = val; 73 | if (val < st[node].mn) st[node].mn = val; 74 | else if (val < st[node].mn2) st[node].mn2 = val; 75 | } 76 | void apply_max(int node, ll val) { 77 | st[node].sum += (val - st[node].mn) * st[node].mn_cnt; 78 | st[node].mn = val; 79 | if (val > st[node].mx) st[node].mx = val; 80 | else if (val > st[node].mx2) st[node].mx2 = val; 81 | } 82 | void combine(int node) { 83 | st[node].sum = st[ln(node)].sum + st[rn(node)].sum; 84 | if (st[ln(node)].mx > st[rn(node)].mx) { 85 | st[node].mx = st[ln(node)].mx; 86 | st[node].mx2 = max(st[ln(node)].mx2, st[rn(node)].mx); 87 | st[node].mx_cnt = st[ln(node)].mx_cnt; 88 | } 89 | else if (st[rn(node)].mx > st[ln(node)].mx) { 90 | st[node].mx = st[rn(node)].mx; 91 | st[node].mx2 = max(st[rn(node)].mx2, st[ln(node)].mx); 92 | st[node].mx_cnt = st[rn(node)].mx_cnt; 93 | } 94 | else { 95 | st[node].mx = st[ln(node)].mx; 96 | st[node].mx2 = max(st[ln(node)].mx2, st[rn(node)].mx2); 97 | st[node].mx_cnt = st[ln(node)].mx_cnt + st[rn(node)].mx_cnt; 98 | } 99 | if (st[ln(node)].mn < st[rn(node)].mn) { 100 | st[node].mn = st[ln(node)].mn; 101 | st[node].mn2 = min(st[ln(node)].mn2, st[rn(node)].mn); 102 | st[node].mn_cnt = st[ln(node)].mn_cnt; 103 | } 104 | else if (st[rn(node)].mn < st[ln(node)].mn) { 105 | st[node].mn = st[rn(node)].mn; 106 | st[node].mn2 = min(st[rn(node)].mn2, st[ln(node)].mn); 107 | st[node].mn_cnt = st[rn(node)].mn_cnt; 108 | } 109 | else { 110 | st[node].mn = st[ln(node)].mn; 111 | st[node].mn2 = min(st[ln(node)].mn2, st[rn(node)].mn2); 112 | st[node].mn_cnt = st[ln(node)].mn_cnt + st[rn(node)].mn_cnt; 113 | } 114 | } 115 | void propagate(int node, int start, int end) { 116 | if (start == end) return; 117 | int mid = (start + end) / 2; 118 | if (st[node].addval) { 119 | apply_add(ln(node), start, mid, st[node].addval); 120 | apply_add(rn(node), mid + 1, end, st[node].addval); 121 | st[node].addval = 0; 122 | } 123 | if (st[node].mx < st[ln(node)].mx) apply_min(ln(node), st[node].mx); 124 | if (st[node].mx < st[rn(node)].mx) apply_min(rn(node), st[node].mx); 125 | if (st[node].mn > st[ln(node)].mn) apply_max(ln(node), st[node].mn); 126 | if (st[node].mn > st[rn(node)].mn) apply_max(rn(node), st[node].mn); 127 | } 128 | void build(vector &arr, int node, int start, int end) { 129 | if (start == end) { 130 | st[node] = tdata(arr[start]); 131 | return; 132 | } 133 | int mid = (start + end) / 2; 134 | build(arr, ln(node), start, mid); 135 | build(arr, rn(node), mid + 1, end); 136 | combine(node); 137 | } 138 | void update_add(int node, int start, int end, int l, int r, ll val) { 139 | propagate(node, start, end); 140 | if (r < start || end < l) return; 141 | if (l <= start && end <= r) { 142 | apply_add(node, start, end, val); 143 | return; 144 | } 145 | int mid = (start + end) / 2; 146 | update_add(ln(node), start, mid, l, r, val); 147 | update_add(rn(node), mid + 1, end, l, r, val); 148 | combine(node); 149 | } 150 | void update_min(int node, int start, int end, int l, int r, ll val) { 151 | propagate(node, start, end); 152 | if (r < start || end < l || st[node].mx <= val) return; 153 | if (l <= start && end <= r && st[node].mx2 < val) { 154 | apply_min(node, val); 155 | return; 156 | } 157 | int mid = (start + end) / 2; 158 | update_min(ln(node), start, mid, l, r, val); 159 | update_min(rn(node), mid + 1, end, l, r, val); 160 | combine(node); 161 | } 162 | void update_max(int node, int start, int end, int l, int r, ll val) { 163 | propagate(node, start, end); 164 | if (r < start || end < l || st[node].mn >= val) return; 165 | if (l <= start && end <= r && st[node].mn2 > val) { 166 | apply_max(node, val); 167 | return; 168 | } 169 | int mid = (start + end) / 2; 170 | update_max(ln(node), start, mid, l, r, val); 171 | update_max(rn(node), mid + 1, end, l, r, val); 172 | combine(node); 173 | } 174 | tdata query(int node, int start, int end, int l, int r) { 175 | propagate(node, start, end); 176 | if (r < start || end < l) return tdata(); 177 | if (l <= start && end <= r) return st[node]; 178 | int mid = (start + end) / 2; 179 | return tdata(query(ln(node), start, mid, l, r), query(rn(node), mid + 1, end, l, r)); 180 | } 181 | void update_add(int l, int r, ll val) {update_add(1, 0, n - 1, l, r, val);} 182 | void update_min(int l, int r, ll val) {update_min(1, 0, n - 1, l, r, val);} 183 | void update_max(int l, int r, ll val) {update_max(1, 0, n - 1, l, r, val);} 184 | tdata query(int l, int r) {return query(1, 0, n - 1, l, r);} 185 | }; 186 | 187 | void solve() { 188 | int n, q; cin >> n >> q; 189 | vector a(n); 190 | for (int i = 0; i < n; i++) cin >> a[i]; 191 | segtree st(a); 192 | while (q--) { 193 | int t, l, r; cin >> t >> l >> r; r--; 194 | if (t == 0) { 195 | ll x; cin >> x; 196 | st.update_min(l, r, x); 197 | } 198 | else if (t == 1) { 199 | ll x; cin >> x; 200 | st.update_max(l, r, x); 201 | } 202 | else if (t == 2) { 203 | ll x; cin >> x; 204 | st.update_add(l, r, x); 205 | } 206 | else { 207 | cout << st.query(l, r).sum << "\n"; 208 | } 209 | } 210 | } 211 | 212 | int main() { 213 | ios_base::sync_with_stdio(0); 214 | cin.tie(0); cout.tie(0); 215 | // freopen("input.txt", "r", stdin); 216 | // freopen("output.txt", "w", stdout); 217 | 218 | int tc = 1; 219 | // cin >> tc; 220 | for (int t = 1; t <= tc; t++) { 221 | // cout << "Case #" << t << ": "; 222 | solve(); 223 | } 224 | } -------------------------------------------------------------------------------- /Data Structures/Sparse Table.cpp: -------------------------------------------------------------------------------- 1 | // Answer range query for static array 2 | // Time complexity: O(nlogn) construction, O(logn) query 3 | // Can be modified to be O(1) query for some queries (i.e minimum/maximum, gcd) 4 | // Problem link: https://cses.fi/problemset/task/1647/, https://cses.fi/problemset/task/1650 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 2e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | const int MAX_L = 18; 19 | 20 | int n, q; 21 | int arr[MAX_N], dp[MAX_N][MAX_L]; 22 | 23 | void build_sparse_table() { 24 | for (int i = 1; i <= n; i++) 25 | dp[i][0] = arr[i]; 26 | for (int j = 1; j < MAX_L; j++) 27 | for (int i = 1; i + (1 << j) <= n + 1; i++) 28 | dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); 29 | // dp[i][j] = dp[i][j - 1] ^ dp[i + (1 << (j - 1))][j - 1]; 30 | } 31 | 32 | int lg(int x) { 33 | return 32 - __builtin_clz(x) - 1; 34 | } 35 | 36 | int min_query(int l, int r) { // O(1) 37 | int k = lg(r - l + 1); 38 | return min(dp[l][k], dp[r - (1 << k) + 1][k]); 39 | } 40 | 41 | int xor_query(int l, int r) { // O(logn) 42 | int k = r - l + 1, ans = 0; 43 | for (int i = 0; i < MAX_L; i++) { 44 | if (k & (1 << i)) { 45 | ans ^= dp[l][i]; 46 | l += (1 << i); 47 | } 48 | } 49 | return ans; 50 | } 51 | 52 | void solve() { 53 | cin >> n >> q; 54 | for (int i = 1; i <= n; i++) cin >> arr[i]; 55 | build_sparse_table(); 56 | while (q--) { 57 | int l, r; cin >> l >> r; 58 | cout << min_query(l, r) << "\n"; 59 | } 60 | } 61 | 62 | int main() { 63 | ios_base::sync_with_stdio(0); 64 | cin.tie(0); cout.tie(0); 65 | // freopen("input.txt", "r", stdin); 66 | // freopen("output.txt", "w", stdout); 67 | 68 | int tc; tc = 1; 69 | for (int t = 1; t <= tc; t++) { 70 | // cout << "Case #" << t << ": "; 71 | solve(); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Data Structures/Suffix Array.cpp: -------------------------------------------------------------------------------- 1 | // Suffix Array: storing all suffixes of a string, useful for many string-related problems 2 | // Problem link: https://www.spoj.com/problems/SUBST1/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | 17 | 18 | void solve() { 19 | string s; cin >> s; s += "$"; 20 | int n = s.size(); 21 | vector p(n), c(n); 22 | vector> a(n); 23 | for (int i = 0; i < n; i++) a[i] = {s[i], i}; 24 | sort(a.begin(), a.end()); 25 | for (int i = 0; i < n; i++) p[i] = a[i].second; 26 | for (int i = 1; i < n; i++) c[p[i]] = (a[i].first == a[i - 1].first) ? c[p[i - 1]] : c[p[i - 1]] + 1; 27 | for (int k = 0; (1 << k) < n; k++) { 28 | for (int i = 0; i < n; i++) p[i] = (p[i] - (1 << k) + n) % n; 29 | vector np(n), nc(n), cnt(n), pos(n); 30 | for (int x : p) cnt[c[x]]++; 31 | for (int i = 1; i < n; i++) pos[i] = pos[i - 1] + cnt[i - 1]; 32 | for (int x : p) np[pos[c[x]]++] = x; 33 | p = np; 34 | for (int i = 1; i < n; i++) { 35 | pair cur = {c[p[i]], c[(p[i] + (1 << k)) % n]}; 36 | pair pre = {c[p[i - 1]], c[(p[i - 1] + (1 << k)) % n]}; 37 | nc[p[i]] = (cur == pre) ? nc[p[i - 1]] : nc[p[i - 1]] + 1; 38 | } 39 | c = nc; 40 | } 41 | vector lcp(n); 42 | for (int i = 0, k = 0; i < n - 1; i++, k = max(k - 1, 0)) { 43 | int pi = c[i], j = p[pi - 1]; 44 | while (s[i + k] == s[j + k]) k++; 45 | lcp[pi] = k; 46 | } 47 | 48 | ll ans = 0; 49 | for (int i = 0; i < n; i++) ans += (n - p[i] - 1) - lcp[i]; 50 | cout << ans << "\n"; 51 | } 52 | 53 | int main() { 54 | ios_base::sync_with_stdio(0); 55 | cin.tie(0); cout.tie(0); 56 | // freopen("input.txt", "r", stdin); 57 | // freopen("output.txt", "w", stdout); 58 | 59 | int tc; cin >> tc; 60 | for (int t = 1; t <= tc; t++) { 61 | // cout << "Case #" << t << ": "; 62 | solve(); 63 | } 64 | } -------------------------------------------------------------------------------- /Data Structures/Treap.cpp: -------------------------------------------------------------------------------- 1 | // Treap data structure supporting split and merge function 2 | // Problem link: https://codeforces.com/gym/102787/problem/A 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 17 | struct tdata { 18 | int val, pri, sz; 19 | tdata *ln, *rn; 20 | tdata(int val): val(val), pri(rng()), sz(1), ln(), rn() {} 21 | }; 22 | int sz(tdata *node) {return node ? node->sz : 0;} 23 | void propagate(tdata *node) { 24 | if (!node) return; 25 | } 26 | void combine(tdata *node) { 27 | if (!node) return; 28 | propagate(node->ln); propagate(node->rn); 29 | node->sz = sz(node->ln) + sz(node->rn) + 1; 30 | } 31 | void heapify(tdata *node) { 32 | if (!node) return; 33 | auto mx = node; 34 | if (node->ln && node->ln->pri > node->pri) mx = node; 35 | if (node->rn && node->rn->pri > node->pri) mx = node; 36 | if (node != mx) { 37 | swap(node->pri, mx->pri); 38 | heapify(mx); 39 | } 40 | } 41 | tdata* build(vector &arr, int start, int end) { 42 | if (start > end) return NULL; 43 | int mid = (start + end) / 2; 44 | auto node = new tdata(arr[mid]); 45 | node->ln = build(arr, start, mid - 1); 46 | node->rn = build(arr, mid + 1, end); 47 | heapify(node); combine(node); 48 | return node; 49 | } 50 | void split(tdata *node, tdata *&ln, tdata *&rn, int k) { // k nodes to ln 51 | propagate(node); 52 | if (!node) { 53 | ln = rn = NULL; 54 | return; 55 | } 56 | if (sz(node->ln) >= k) split(node->ln, ln, node->ln, k), rn = node; 57 | else split(node->rn, node->rn, rn, k - sz(node->ln) - 1), ln = node; 58 | combine(node); 59 | } 60 | void merge(tdata *&node, tdata *ln, tdata *rn) { 61 | propagate(ln); propagate(rn); 62 | if (!ln || !rn) { 63 | node = ln ? ln : rn; 64 | return; 65 | } 66 | if (ln->pri > rn->pri) merge(ln->rn, ln->rn, rn), node = ln; 67 | else merge(rn->ln, ln, rn->ln), node = rn; 68 | combine(node); 69 | } 70 | void print(tdata *node) { 71 | if (!node) return; 72 | print(node->ln); 73 | cout << node->val << " "; 74 | print(node->rn); 75 | } 76 | 77 | void solve() { 78 | int n; cin >> n; 79 | vector arr(n); 80 | iota(arr.begin(), arr.end(), 1); 81 | auto tr = build(arr, 0, n - 1); 82 | for (int i = 0; i < n; i++) { 83 | int a, b; cin >> a >> b; 84 | if (a >= b) continue; 85 | int len = min(b - a, n - b + 1); 86 | tdata *p1, *p2, *p3, *p4, *p5; 87 | split(tr, p3, p4, b - 1); 88 | split(p4, p4, p5, len); 89 | split(p3, p1, p2, a - 1); 90 | split(p2, p2, p3, len); 91 | merge(tr, p1, p4); 92 | merge(tr, tr, p3); 93 | merge(tr, tr, p2); 94 | merge(tr, tr, p5); 95 | } 96 | print(tr); 97 | cout << "\n"; 98 | } 99 | 100 | int main() { 101 | ios_base::sync_with_stdio(0); 102 | cin.tie(0); cout.tie(0); 103 | // freopen("input.txt", "r", stdin); 104 | // freopen("output.txt", "w", stdout); 105 | 106 | int tc = 1; 107 | // cin >> tc; 108 | for (int t = 1; t <= tc; t++) { 109 | // cout << "Case #" << t << ": "; 110 | solve(); 111 | } 112 | } -------------------------------------------------------------------------------- /Data Structures/Tree Query.cpp: -------------------------------------------------------------------------------- 1 | // Query on tree using eulerian ordering and fenwick tree 2 | // Problem link: https://cses.fi/problemset/task/1137/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | #define LSOne(S) ((S) & (-S)) 17 | 18 | int n, q, arr[MAX_N], tin[MAX_N], tout[MAX_N], timer; 19 | ll ft[2 * MAX_N]; 20 | vector adj[MAX_N]; 21 | 22 | void update(int x, int v) { 23 | for (; x <= 2 * n; x += LSOne(x)) 24 | ft[x] += v; 25 | } 26 | 27 | ll sum(int x) { 28 | ll res = 0; 29 | for (; x; x -= LSOne(x)) 30 | res += ft[x]; 31 | return res; 32 | } 33 | 34 | ll rsq(int a, int b) { 35 | return sum(b) - sum(a - 1); 36 | } 37 | 38 | void dfs(int u, int p = 0) { 39 | tin[u] = ++timer; 40 | for (int v : adj[u]) { 41 | if (v != p) { 42 | dfs(v, u); 43 | } 44 | } 45 | tout[u] = ++timer; 46 | } 47 | 48 | void solve() { 49 | cin >> n >> q; 50 | for (int i = 1; i <= n; i++) cin >> arr[i]; 51 | for (int i = 0; i < n - 1; i++) { 52 | int u, v; cin >> u >> v; 53 | adj[u].push_back(v); 54 | adj[v].push_back(u); 55 | } 56 | dfs(1); 57 | for (int i = 1; i <= n; i++) { 58 | update(tin[i], arr[i]); 59 | update(tout[i], arr[i]); 60 | } 61 | while (q--) { 62 | int t; cin >> t; 63 | if (t == 1) { 64 | int s, x; cin >> s >> x; 65 | update(tin[s], x - arr[s]); 66 | update(tout[s], x - arr[s]); 67 | arr[s] = x; 68 | } 69 | else { 70 | int s; cin >> s; 71 | cout << rsq(tin[s], tout[s]) / 2 << "\n"; 72 | } 73 | } 74 | } 75 | 76 | int main() { 77 | ios_base::sync_with_stdio(0); 78 | cin.tie(0); cout.tie(0); 79 | // freopen("input.txt", "r", stdin); 80 | // freopen("output.txt", "w", stdout); 81 | 82 | int tc; tc = 1; 83 | for (int t = 1; t <= tc; t++) { 84 | // cout << "Case #" << t << ": "; 85 | solve(); 86 | } 87 | } -------------------------------------------------------------------------------- /Data Structures/Trie.cpp: -------------------------------------------------------------------------------- 1 | // Prefix tree: storing strings based on their common prefix 2 | // Problem link: https://codingcompetitions.withgoogle.com/kickstart/round/000000000019ffc7/00000000001d3ff3 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | const int MAX_S = 2e6; // total number of characters in all strings 17 | const int MAX_C = 26; // total number of distinct characters 18 | 19 | int N, K, num, ans; 20 | int trie[MAX_S][MAX_C], cnt[MAX_S]; 21 | 22 | // initially all values in trie are 0 (not allocated) 23 | // cnt[u] = number of strings that end at node u in the trie => this is to mark the end of a string in the trie 24 | // "num" stores the total number of allocated nodes in the trie 25 | 26 | void dfs(int u = 0, int d = 0) { 27 | for (int v = 0; v < 26; v++) { 28 | if (trie[u][v]) { 29 | dfs(trie[u][v], d + 1); 30 | // now cnt[u] stores the total number of strings that has a common prefix from the root to node u 31 | cnt[u] += cnt[trie[u][v]]; 32 | } 33 | } 34 | // greedily dividing into groups of K 35 | while (cnt[u] >= K) { 36 | cnt[u] -= K; 37 | ans += d; 38 | } 39 | } 40 | 41 | // insert a string into the trie 42 | void insert(string s) { 43 | // start at the root node 44 | int u = 0; 45 | for (char c : s) { 46 | // if this node has not been allocated, then allocate the node and increase num by 1 47 | if (!trie[u][c - 'A']) trie[u][c - 'A'] = ++num; 48 | // move to the next node 49 | u = trie[u][c - 'A']; 50 | } 51 | // mark the end of string 52 | cnt[u]++; 53 | } 54 | 55 | // check if a string exist in the trie 56 | bool search(string s) { 57 | int u = 0; 58 | for (char c : s) { 59 | if (!trie[u][c - 'A']) return false; 60 | u = trie[u][c - 'A']; 61 | } 62 | return cnt[u] > 0; 63 | } 64 | 65 | void solve() { 66 | // need to reset after each test case 67 | ans = 0; num = 0; 68 | memset(trie, 0, sizeof trie); 69 | memset(cnt, 0, sizeof cnt); 70 | 71 | cin >> N >> K; 72 | for (int i = 0; i < N; i++) { 73 | string s; cin >> s; 74 | insert(s); 75 | } 76 | dfs(); 77 | cout << ans << "\n"; 78 | } 79 | 80 | int main() { 81 | ios_base::sync_with_stdio(0); 82 | cin.tie(0); cout.tie(0); 83 | // freopen("input.txt", "r", stdin); 84 | // freopen("output.txt", "w", stdout); 85 | 86 | int tc; cin >> tc; 87 | for (int t = 1; t <= tc; t++) { 88 | cout << "Case #" << t << ": "; 89 | solve(); 90 | } 91 | } -------------------------------------------------------------------------------- /Dynamic Programming/(0-1) Knapsack.cpp: -------------------------------------------------------------------------------- 1 | // Given a list of items with their weights and values 2 | // Find the maximum value one can obtain with a total weight limit 3 | // Time complexity: O(nw) 4 | // Problem link: https://cses.fi/problemset/task/1158 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | 19 | 20 | void solve() { 21 | int n, w; cin >> n >> w; 22 | int weight[n], val[n]; 23 | for (int i = 0; i < n; i++) cin >> weight[i]; 24 | for (int i = 0; i < n; i++) cin >> val[i]; 25 | 26 | int dp[w + 1] = {}; 27 | for (int i = 0; i < n; i++) 28 | for (int j = w; j >= weight[i]; j--) 29 | dp[j] = max(dp[j], dp[j - weight[i]] + val[i]); 30 | cout << dp[w] << "\n"; 31 | } 32 | 33 | int main() { 34 | ios_base::sync_with_stdio(0); 35 | cin.tie(0); cout.tie(0); 36 | // freopen("input.txt", "r", stdin); 37 | // freopen("output.txt", "w", stdout); 38 | 39 | int tc; tc = 1; 40 | for (int t = 1; t <= tc; t++) { 41 | // cout << "Case #" << t << ": "; 42 | solve(); 43 | } 44 | } -------------------------------------------------------------------------------- /Dynamic Programming/1D Max Sum (Kanade).cpp: -------------------------------------------------------------------------------- 1 | // Given an array of integers, find the maximum sum subarray 2 | // Time complexity: O(n) 3 | // Problem link: https://cses.fi/problemset/task/1643 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | 18 | 19 | void solve() { 20 | int n; cin >> n; 21 | // set to -LINF to return non-empty maximum subarray sum, otherwise set to 0 22 | ll ans = -LINF, cur = -LINF; 23 | for (int i = 0; i < n; i++) { 24 | ll x; cin >> x; 25 | cur = max(x, cur + x); 26 | // cur = max(0, cur + x); 27 | ans = max(ans, cur); 28 | } 29 | cout << ans << "\n"; 30 | } 31 | 32 | int main() { 33 | ios_base::sync_with_stdio(0); 34 | cin.tie(0); cout.tie(0); 35 | // freopen("input.txt", "r", stdin); 36 | // freopen("output.txt", "w", stdout); 37 | 38 | int tc; tc = 1; 39 | for (int t = 1; t <= tc; t++) { 40 | // cout << "Case #" << t << ": "; 41 | solve(); 42 | } 43 | } -------------------------------------------------------------------------------- /Dynamic Programming/2D Max Sum.cpp: -------------------------------------------------------------------------------- 1 | // Given a 2D array of integers, find the maximum sum 2D subarray 2 | // Performing the 1D maxsum algorithm on the columns of all O(n^2) consecutive set of rows 3 | // Time complexity: O(n^3) 4 | // Problem link: https://vjudge.net/problem/UVA-108 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | 19 | 20 | void solve() { 21 | int n; cin >> n; 22 | ll ps[n + 1][n + 1] = {}; 23 | // Creating a prefix sum table (horizontally) 24 | for (int i = 1; i <= n; i++) { 25 | for (int j = 1; j <= n; j++) { 26 | cin >> ps[i][j]; 27 | ps[i][j] += ps[i][j - 1]; 28 | } 29 | } 30 | 31 | // 2D max sum subarray 32 | ll ans = 0; 33 | for (int l = 1; l <= n; l++) { // looping through all pairs of columns, running 1D maxsum on a column 34 | for (int r = l; r <= n; r++) { 35 | ll cur = 0; 36 | for (int i = 1; i <= n; i++) { 37 | ll x = ps[i][r] - ps[i][l - 1]; 38 | cur = max(0ll, cur + x); 39 | ans = max(ans, cur); 40 | } 41 | } 42 | } 43 | cout << ans << "\n"; 44 | } 45 | 46 | int main() { 47 | ios_base::sync_with_stdio(0); 48 | cin.tie(0); cout.tie(0); 49 | // freopen("input.txt", "r", stdin); 50 | // freopen("output.txt", "w", stdout); 51 | 52 | int tc; tc = 1; 53 | for (int t = 1; t <= tc; t++) { 54 | // cout << "Case #" << t << ": "; 55 | solve(); 56 | } 57 | } -------------------------------------------------------------------------------- /Dynamic Programming/Coin Change.cpp: -------------------------------------------------------------------------------- 1 | // Given n different values of coins 2 | // 1) Find the number of distinct ways to sum up to x 3 | // 2) Find the number of distinct "ordered" ways to sum up to x 4 | // 3) Find the minimum number of coins required to sum up to x 5 | // Time complexity: O(nx) 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | #define ar array 12 | #define ll long long 13 | 14 | const int MAX_N = 1e5 + 1; 15 | const int MOD = 1e9 + 7; 16 | const int INF = 1e9; 17 | const ll LINF = 1e18; 18 | 19 | 20 | 21 | void solve() { 22 | int n, x; cin >> n >> x; 23 | int arr[n]; 24 | for (int i = 0; i < n; i++) cin >> arr[i]; 25 | 26 | // 1) Problem link: https://cses.fi/problemset/task/1635 27 | vector dp(x + 1, 0); 28 | dp[0] = 1; 29 | for (int i = 1; i <= x; i++) 30 | for (int j : arr) 31 | if (i - j >= 0) 32 | dp[i] = (dp[i] + dp[i - j]) % MOD; 33 | cout << dp[x] << "\n"; 34 | 35 | // 2) Problem link: https://cses.fi/problemset/task/1636 36 | vector dp(x + 1, 0); 37 | dp[0] = 1; 38 | for (int j : arr) 39 | for (int i = 1; i <= x; i++) 40 | if (i - j >= 0) 41 | dp[i] = (dp[i] + dp[i - j]) % MOD; 42 | cout << dp[x] << "\n"; 43 | 44 | // 3) Problem link: https://cses.fi/problemset/task/1634 45 | vector dp(x + 1, INF); 46 | dp[0] = 0; 47 | for (int i = 1; i <= x; i++) 48 | for (int j : arr) 49 | if (i - j >= 0) 50 | dp[i] = min(dp[i], dp[i - j] + 1); 51 | cout << (dp[x] == INF ? -1 : dp[x]) << "\n"; 52 | } 53 | 54 | int main() { 55 | ios_base::sync_with_stdio(0); 56 | cin.tie(0); cout.tie(0); 57 | // freopen("input.txt", "r", stdin); 58 | // freopen("output.txt", "w", stdout); 59 | 60 | int tc; tc = 1; 61 | for (int t = 1; t <= tc; t++) { 62 | // cout << "Case #" << t << ": "; 63 | solve(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /Dynamic Programming/Convex Hull Trick & Li-Chao Segment Tree.cpp: -------------------------------------------------------------------------------- 1 | // Use Convex Hull Trick (CHT) to optimize a DP solution 2 | // Alternatively, use Li-Chao Segment Tree 3 | // Problem link: https://atcoder.jp/contests/dp/tasks/dp_z 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | struct lichaotree { 18 | struct line { 19 | ll m, c; 20 | line(ll m, ll c): m(m), c(c) {} 21 | ll operator()(ll x) {return m * x + c;} 22 | }; 23 | struct tdata { 24 | line seg; 25 | tdata *ln, *rn; 26 | tdata(line seg): seg(seg) {} 27 | }; 28 | int n; tdata *st; 29 | lichaotree(int n): n(n) {st = new tdata({INF, INF});} 30 | void update(tdata *node, int start, int end, line y) { 31 | int mid = (start + end) / 2; 32 | bool b1 = y(start) < node->seg(start); 33 | bool b2 = y(mid) < node->seg(mid); 34 | if (b2) swap(node->seg, y); 35 | if (start + 1 == end) return; 36 | if (b1 != b2) { 37 | if (node->ln) update(node->ln, start, mid, y); 38 | else node->ln = new tdata(y); 39 | } 40 | else { 41 | if (node->rn) update(node->rn, mid, end, y); 42 | else node->rn = new tdata(y); 43 | } 44 | } 45 | ll query(tdata *node, ll start, ll end, ll x) { 46 | if (start + 1 == end) return node->seg(x); 47 | ll mid = (start + end) / 2; 48 | if (x < mid && node->ln) return min(node->seg(x), query(node->ln, start, mid, x)); 49 | else if (node->rn) return min(node->seg(x), query(node->rn, mid, end, x)); 50 | return node->seg(x); 51 | } 52 | void update(line y) {update(st, 0, n, y);} 53 | ll query(int x) {return query(st, 0, n, x);} 54 | }; 55 | 56 | struct convexhull { 57 | struct line { 58 | ll m, c; 59 | line(ll m, ll c): m(m), c(c) {} 60 | ll operator()(ll x) {return m * x + c;} 61 | }; 62 | deque dq; 63 | bool check(line p1, line p2, line p3) { 64 | return (p2.m - p1.m) * (p3.c - p2.c) >= (p3.m - p2.m) * (p2.c - p1.c); 65 | } 66 | void add(line y) { // decreasing slope 67 | while (dq.size() >= 2 && check(dq[dq.size() - 2], dq[dq.size() - 1], y)) dq.pop_back(); 68 | dq.push_back(y); 69 | } 70 | ll query(ll x) { // min query, increasing x 71 | while (dq.size() >= 2 && dq[0](x) >= dq[1](x)) dq.pop_front(); 72 | return dq[0](x); 73 | } 74 | ll query(ll x) { // min query, any x 75 | int lo = -1, hi = dq.size() - 1; 76 | while (lo + 1 < hi) { 77 | int mid = (lo + hi) / 2; 78 | if (dq[mid](x) >= dq[mid + 1](x)) lo = mid; 79 | else hi = mid; 80 | } 81 | return dq[hi](x); 82 | } 83 | }; 84 | 85 | void solve() { 86 | int n; ll c; cin >> n >> c; 87 | vector a(n); 88 | for (int i = 0; i < n; i++) cin >> a[i]; 89 | vector dp(n, LINF); 90 | dp[0] = 0; 91 | lichaotree st(1e6 + 1); 92 | // convexhull cht; 93 | for (int i = 1; i < n; i++) { 94 | // Naive O(n^2) 95 | // for (int j = 0; j < i; j++) { 96 | // dp[i] = min(dp[i], dp[j] + (a[i] - a[j]) * (a[i] - a[j]) + c); 97 | // } 98 | 99 | // dp[i] = a[i] * a[i] + c + min{-2 * a[j] * a[i] + a[j] * a[j] + dp[j]} 100 | // Better O(nlogn) 101 | 102 | st.update({-2 * a[i - 1], a[i - 1] * a[i - 1] + dp[i - 1]}); 103 | dp[i] = a[i] * a[i] + c + st.query(a[i]); 104 | 105 | // cht.add({- 2 * a[i - 1], a[i - 1] * a[i - 1] + dp[i - 1]}); 106 | // dp[i] = a[i] * a[i] + c + cht.query(a[i]); 107 | } 108 | cout << dp[n - 1] << "\n"; 109 | } 110 | 111 | int main() { 112 | ios_base::sync_with_stdio(0); 113 | cin.tie(0); cout.tie(0); 114 | // freopen("input.txt", "r", stdin); 115 | // freopen("output.txt", "w", stdout); 116 | 117 | int tc; tc = 1; 118 | for (int t = 1; t <= tc; t++) { 119 | // cout << "Case #" << t << ": "; 120 | solve(); 121 | } 122 | } -------------------------------------------------------------------------------- /Dynamic Programming/Cutting Sticks.cpp: -------------------------------------------------------------------------------- 1 | // Given a length x and n cutting points, find the minimum cost perform all n cuts 2 | // Cost of a cut is equal to the length of the current stick 3 | // A variation of Matrix Chain Multiplication DP Problem 4 | // Time complexity: O(n^3), can be reduced to O(n^2) with Knuth Optimization 5 | // Problem link: https://vjudge.net/problem/UVA-10003 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | #define ar array 12 | #define ll long long 13 | 14 | const int MAX_N = 50 + 5; 15 | const int MOD = 1e9 + 7; 16 | const int INF = 1e9; 17 | const ll LINF = 1e18; 18 | 19 | int opt[MAX_N][MAX_N]; 20 | 21 | void solve() { 22 | while (true) { 23 | int x; cin >> x; 24 | if (!x) return; 25 | 26 | int n; cin >> n; 27 | int arr[n + 2]; 28 | // adding the beginning point and the ending point 29 | arr[0] = 0; arr[n + 1] = x; 30 | for (int i = 1; i <= n; i++) cin >> arr[i]; 31 | vector> dp(n + 2, vector(n + 2, INF)); 32 | for (int i = 0; i < n + 1; i++) { 33 | dp[i][i + 1] = 0; 34 | opt[i][i + 1] = i; 35 | } 36 | // range dp 37 | for (int i = n + 1; i >= 0; i--) { 38 | for (int j = i; j <= n + 1; j++) { 39 | for (int k = i + 1; k < j; k++) { 40 | if (dp[i][j] > dp[i][k] + dp[k][j] + arr[j] - arr[i]) { 41 | dp[i][j] = dp[i][k] + dp[k][j] + arr[j] - arr[i]; 42 | } 43 | } 44 | // Knuth Optimization (only need to change 2 lines) 45 | // Condition: dp[i][j] = min{i < k < j}(dp[i][k] + dp[k][j]) + C[i][j] 46 | // for (int k = opt[i][j - 1]; k <= opt[i + 1][j]; k++) { 47 | // if (dp[i][j] > dp[i][k] + dp[k][j] + arr[j] - arr[i]) { 48 | // dp[i][j] = dp[i][k] + dp[k][j] + arr[j] - arr[i]; 49 | // opt[i][j] = k; 50 | // } 51 | // } 52 | } 53 | } 54 | cout << "The minimum cutting is " << dp[0][n + 1] << ".\n"; 55 | } 56 | } 57 | 58 | int main() { 59 | ios_base::sync_with_stdio(0); 60 | cin.tie(0); cout.tie(0); 61 | // freopen("input.txt", "r", stdin); 62 | // freopen("output.txt", "w", stdout); 63 | 64 | int tc; tc = 1; 65 | for (int t = 1; t <= tc; t++) { 66 | // cout << "Case #" << t << ": "; 67 | solve(); 68 | } 69 | } -------------------------------------------------------------------------------- /Dynamic Programming/D&C Trick.cpp: -------------------------------------------------------------------------------- 1 | // Use Divide & Conquer (D&C) to optimize a DP solution 2 | // Problem link: https://www.spoj.com/problems/LARMY/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 5e3 + 1; 12 | const ll MOD = 1e9 + 7; 13 | const ll INF = 1e9; 14 | 15 | int n, m, a[MAX_N]; 16 | int ps[MAX_N][MAX_N], dp[MAX_N][MAX_N]; 17 | // dp[i][j] = minimum unhappiness when splitting the first j-th people into i rows 18 | 19 | int cost(int i, int j) { 20 | return ps[j][j] - ps[i - 1][j] - ps[j][i - 1] + ps[i - 1][i - 1]; 21 | } 22 | 23 | void dac(int i, int l, int r, int ql, int qr) { 24 | if (l > r) return; 25 | int mid = (l + r) / 2; 26 | ar res = {INF, INF}; 27 | for (int k = ql; k <= min(mid, qr); k++) { 28 | res = min(res, {dp[i - 1][k - 1] + cost(k, mid), k}); 29 | } 30 | dp[i][mid] = res[0]; 31 | dac(i, l, mid - 1, ql, res[1]); 32 | dac(i, mid + 1, r, res[1], qr); 33 | } 34 | 35 | void solve() { 36 | cin >> n >> m; 37 | for (int i = 1; i <= n; i++) cin >> a[i]; 38 | for (int i = 1; i <= n; i++) { 39 | for (int j = 1; j < i; j++) { 40 | ps[i][j] = a[j] > a[i]; 41 | } 42 | } 43 | for (int i = 1; i <= n; i++) { 44 | for (int j = 1; j <= n; j++) { 45 | ps[i][j] = ps[i - 1][j] + ps[i][j - 1] - ps[i - 1][j - 1] + ps[i][j]; 46 | } 47 | } 48 | memset(dp, 0x3f, sizeof dp); 49 | dp[0][0] = 0; 50 | 51 | // Naive O(mn^2) by directly applying dp[i][j] = min{dp[i - 1][k - 1] + cost(k, j)} for 1 <= k <= j 52 | // for (int i = 1; i <= m; i++) { 53 | // for (int j = 1; j <= n; j++) { 54 | // for (int k = 1; k <= j; k++) { 55 | // dp[i][j] = min(dp[i][j], dp[i - 1][k - 1] + cost(k, j)); 56 | // } 57 | // } 58 | // } 59 | 60 | // Optimised O(mnlogn) using D&C 61 | for (int i = 1; i <= m; i++) dac(i, i, n, i, n); 62 | 63 | cout << dp[m][n] << "\n"; 64 | } 65 | 66 | int main() { 67 | ios_base::sync_with_stdio(0); 68 | cin.tie(0); cout.tie(0); 69 | int tc = 1; 70 | // cin >> tc; 71 | for (int t = 1; t <= tc; t++) { 72 | // cout << "Case #" << t << ": "; 73 | solve(); 74 | } 75 | } -------------------------------------------------------------------------------- /Dynamic Programming/Deque Trick.cpp: -------------------------------------------------------------------------------- 1 | // Optimise from O(NK^2) to O(NK) by answering min/max queries among k consecutive elements in O(1) in DP transition 2 | // Problem link: https://codeforces.com/contest/1077/problem/F2 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const ll MOD = 1e9 + 7; 13 | const ll INF = 1e9; 14 | 15 | 16 | 17 | void solve() { 18 | int n, k, x; cin >> n >> k >> x; 19 | vector a(n + 1); 20 | for (int i = 1; i <= n; i++) cin >> a[i]; 21 | ll dp[n + 1][x + 1]; // dp[i][j] = answer using j pictures from the first i-th pictures 22 | memset(dp, -0x3f, sizeof dp); 23 | dp[0][0] = 0; 24 | for (int j = 1; j <= x; j++) { 25 | deque> dq; // {id, value} 26 | dq.push_back({j - 1, dp[j - 1][j - 1]}); 27 | for (int i = j; i <= n; i++) { 28 | while (dq.size() && dq.front()[0] < i - k) dq.pop_front(); 29 | dp[i][j] = dq.front()[1] + a[i]; 30 | while (dq.size() && dp[i][j - 1] >= dq.back()[1]) dq.pop_back(); 31 | dq.push_back({i, dp[i][j - 1]}); 32 | } 33 | 34 | } 35 | ll ans = -1; 36 | for (int i = 0; i < k; i++) ans = max(ans, dp[n - i][x]); 37 | cout << ans << "\n"; 38 | } 39 | 40 | int main() { 41 | ios_base::sync_with_stdio(0); 42 | cin.tie(0); cout.tie(0); 43 | int tc = 1; 44 | // cin >> tc; 45 | for (int t = 1; t <= tc; t++) { 46 | // cout << "Case #" << t << ": "; 47 | solve(); 48 | } 49 | } -------------------------------------------------------------------------------- /Dynamic Programming/Digit DP.cpp: -------------------------------------------------------------------------------- 1 | // Find the sum of the digits of the numbers between a and b (0 <= a <= b <= 1e9) 2 | // Problem link: https://www.spoj.com/problems/CPCRC1C/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | vector num; 17 | ll dp[10][9 * 10][2]; 18 | 19 | // dp[pos][sum][flag] 20 | // pos = current position, starting from the left (0-index) 21 | // sum = sum of all digits till the given position 22 | // flag = the number we are building has already become smaller than b? [0 = no, 1 = yes] 23 | 24 | ll memo(int pos, int sum, int flag) { 25 | if (pos == num.size()) return sum; 26 | if (dp[pos][sum][flag] != -1) return dp[pos][sum][flag]; 27 | 28 | ll res = 0; 29 | int lmt = (flag) ? 9 : num[pos]; 30 | for (int i = 0; i <= lmt; i++) { 31 | int next_flag = (i < lmt) ? 1 : flag; 32 | res += memo(pos + 1, sum + i, next_flag); 33 | } 34 | return dp[pos][sum][flag] = res; 35 | } 36 | 37 | ll calc(int n) { 38 | num.clear(); 39 | while (n) { 40 | num.push_back(n % 10); 41 | n /= 10; 42 | } 43 | reverse(num.begin(), num.end()); 44 | memset(dp, -1, sizeof dp); 45 | return memo(0, 0, 0); 46 | } 47 | 48 | void solve() { 49 | while (true) { 50 | int a, b; cin >> a >> b; 51 | if (a == -1 && b == -1) return; 52 | cout << calc(b) - calc(a - 1) << "\n"; 53 | } 54 | } 55 | 56 | int main() { 57 | ios_base::sync_with_stdio(0); 58 | cin.tie(0); cout.tie(0); 59 | // freopen("input.txt", "r", stdin); 60 | // freopen("output.txt", "w", stdout); 61 | 62 | int tc; tc = 1; 63 | for (int t = 1; t <= tc; t++) { 64 | // cout << "Case #" << t << ": "; 65 | solve(); 66 | } 67 | } -------------------------------------------------------------------------------- /Dynamic Programming/Elevator Rides.cpp: -------------------------------------------------------------------------------- 1 | // Find the minimum of elevator rides to move n people knowing everyone's weight and the elevator's limit 2 | // Time complexity: O(2^n * n) 3 | // Problem link: https://cses.fi/problemset/task/1653 4 | // Use DP with bitmask 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | 19 | 20 | void solve() { 21 | int n, x; cin >> n >> x; 22 | int weight[n]; 23 | for (int i = 0; i < n; i++) cin >> weight[i]; 24 | 25 | ar dp[1 << n]; 26 | // dp[i][0] = the minimum number of rides for bitmask i 27 | // dp[i][1] = the minimum weight of the last ride for bitmask i 28 | dp[0] = {0, 0}; 29 | for (int i = 1; i < (1 << n); i++) { 30 | // upper bound is n + 1 rides 31 | dp[i] = {n + 1, 0}; 32 | for (int j = 0; j < n; j++) { 33 | if (i & (1 << j)) { 34 | auto cur = dp[i ^ (1 << j)]; 35 | if (cur[1] + weight[j] <= x) { // add j to the current ride 36 | cur[1] += weight[j]; 37 | } 38 | else { // reserves a new ride for j 39 | cur[0]++; 40 | cur[1] = weight[j]; 41 | } 42 | dp[i] = min(dp[i], cur); 43 | } 44 | } 45 | } 46 | // if dp[i].second > 0, then the answer is dp[i].first + 1 47 | cout << dp[(1 << n) - 1][0] + (dp[(1 << n) - 1][1] > 0); 48 | } 49 | 50 | int main() { 51 | ios_base::sync_with_stdio(0); 52 | cin.tie(0); cout.tie(0); 53 | // freopen("input.txt", "r", stdin); 54 | // freopen("output.txt", "w", stdout); 55 | 56 | int tc; tc = 1; 57 | for (int t = 1; t <= tc; t++) { 58 | // cout << "Case #" << t << ": "; 59 | solve(); 60 | } 61 | } -------------------------------------------------------------------------------- /Dynamic Programming/Longest Common Subsequence (LCS).cpp: -------------------------------------------------------------------------------- 1 | // Given 2 strings x and y of length n and m, find the the longest common subsequence (LCS) 2 | // Time complexity: O(nm) 3 | // Problem link: https://dunjudge.me/analysis/problems/171/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | 18 | 19 | void solve() { 20 | string x, y; cin >> x >> y; 21 | int n = x.size(), m = y.size(); 22 | int dp[n + 1][m + 1] = {}; 23 | for (int i = 1; i <= n; i++) { 24 | for (int j = 1; j <= m; j++) { 25 | if (x[i - 1] == y[j - 1]) 26 | dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1); 27 | else 28 | dp[i][j] = max({dp[i][j], dp[i - 1][j], dp[i][j - 1]}); 29 | } 30 | } 31 | cout << dp[n][m]; 32 | } 33 | 34 | int main() { 35 | ios_base::sync_with_stdio(0); 36 | cin.tie(0); cout.tie(0); 37 | // freopen("input.txt", "r", stdin); 38 | // freopen("output.txt", "w", stdout); 39 | 40 | int tc; tc = 1; 41 | for (int t = 1; t <= tc; t++) { 42 | // cout << "Case #" << t << ": "; 43 | solve(); 44 | } 45 | } -------------------------------------------------------------------------------- /Dynamic Programming/Longest Increasing Subsequence (LIS).cpp: -------------------------------------------------------------------------------- 1 | // Find the longest increasing subsequence (LIS) in the array of length n 2 | // Time complexity: O(nlogn) 3 | // Problem link: https://cses.fi/problemset/task/1145 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | 18 | 19 | void solve() { 20 | int n; cin >> n; 21 | vector dp; 22 | for (int i = 0; i < n; i++) { 23 | int x; cin >> x; 24 | auto it = lower_bound(dp.begin(), dp.end(), x); 25 | if (it == dp.end()) dp.push_back(x); 26 | else *it = x; 27 | } 28 | cout << dp.size() << "\n"; 29 | } 30 | 31 | int main() { 32 | ios_base::sync_with_stdio(0); 33 | cin.tie(0); cout.tie(0); 34 | // freopen("input.txt", "r", stdin); 35 | // freopen("output.txt", "w", stdout); 36 | 37 | int tc; cin >> tc; 38 | for (int t = 1; t <= tc; t++) { 39 | // cout << "Case #" << t << ": "; 40 | solve(); 41 | } 42 | } -------------------------------------------------------------------------------- /Dynamic Programming/Matrix Chain.cpp: -------------------------------------------------------------------------------- 1 | // Similar to "Cutting Sticks", a variation of Matrix Chain Multiplication DP Problem 2 | // Time complexity: O(n^3) 3 | // Problem link: https://www.spoj.com/problems/MIXTURES/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | 18 | 19 | void solve() { 20 | int n; 21 | while(cin >> n) { 22 | int arr[n][n]; 23 | for (int i = 0; i < n; i++) cin >> arr[i][i]; 24 | int dp[n][n]; 25 | // diagonal dp (another way to achieve the same thing as range dp) 26 | for (int l = 0; l < n; l++) { 27 | for (int i = 0, j = i + l; j < n; i++, j++) { 28 | if (l == 0) dp[i][j] = 0; 29 | else { 30 | dp[i][j] = INF; 31 | for (int k = i; k < j; k++) { 32 | if (dp[i][j] > dp[i][k] + dp[k + 1][j] + arr[i][k] * arr[k + 1][j]) { 33 | dp[i][j] = dp[i][k] + dp[k + 1][j] + arr[i][k] * arr[k + 1][j]; 34 | arr[i][j] = (arr[i][k] + arr[k + 1][j]) % 100; 35 | } 36 | } 37 | } 38 | } 39 | } 40 | cout << dp[0][n - 1] << "\n"; 41 | } 42 | } 43 | 44 | int main() { 45 | ios_base::sync_with_stdio(0); 46 | cin.tie(0); cout.tie(0); 47 | // freopen("input.txt", "r", stdin); 48 | // freopen("output.txt", "w", stdout); 49 | 50 | int tc; tc = 1; 51 | for (int t = 1; t <= tc; t++) { 52 | // cout << "Case #" << t << ": "; 53 | solve(); 54 | } 55 | } -------------------------------------------------------------------------------- /Dynamic Programming/SOS DP.cpp: -------------------------------------------------------------------------------- 1 | // Sum-over-subset dp to optimise from O(4^n) or O(3^n) to O(n*2^n) 2 | // Problem link: https://cses.fi/problemset/task/1654 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MAX_M = 20; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e9; 15 | 16 | int inv(int x) {return x ^ ((1 << MAX_M) - 1);} 17 | 18 | void solve() { 19 | int n; cin >> n; 20 | vector a(n); 21 | vector dp(1 << MAX_M), dp_inv(1 << MAX_M); 22 | for (int &x : a) { 23 | cin >> x; 24 | dp[x]++; 25 | dp_inv[inv(x)]++; 26 | } 27 | for (int i = 0; i < MAX_M; i++) { 28 | for (int mask = 0; mask < (1 << MAX_M); mask++) { 29 | if (mask & (1 << i)) { 30 | dp[mask] += dp[mask ^ (1 << i)]; 31 | dp_inv[mask] += dp_inv[mask ^ (1 << i)]; 32 | } 33 | } 34 | } 35 | for (int x : a) { 36 | cout << dp[x] << " " << dp_inv[inv(x)] << " " << n - dp[inv(x)] << "\n"; 37 | } 38 | } 39 | 40 | int main() { 41 | ios_base::sync_with_stdio(0); 42 | cin.tie(0); cout.tie(0); 43 | int tc = 1; 44 | // cin >> tc; 45 | for (int t = 1; t <= tc; t++) { 46 | // cout << "Case #" << t << ": "; 47 | solve(); 48 | } 49 | } -------------------------------------------------------------------------------- /Dynamic Programming/Traveling Salesman Problem (TSP).cpp: -------------------------------------------------------------------------------- 1 | // Given n cities/nodes, find a minimum weight Hamiltonian Cycle/Tour 2 | // Time complexity: O(2^n * n^2) 3 | // Problem link: https://vjudge.net/problem/UVA-10496 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 11; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | int n, x[MAX_N], y[MAX_N], adj[MAX_N][MAX_N], dp[1 << MAX_N][MAX_N]; 18 | 19 | int tsp(int mask, int u) { 20 | if (mask == (1 << n) - 1) return adj[u][0]; // finish all nodes (bitmask == 11...11) 21 | if (dp[mask][u] != -1) return dp[mask][u]; 22 | 23 | int ans = INF; 24 | // Visit all the unvisited nodes and take the best route 25 | for (int v = 0; v < n; v++) { 26 | if (!(mask & (1 << v))) { // this node is unvisited 27 | int cur = adj[u][v] + tsp(mask | (1 << v), v); 28 | ans = min(ans, cur); 29 | } 30 | } 31 | return dp[mask][u] = ans; 32 | } 33 | 34 | void solve() { 35 | int xs, ys; cin >> xs >> ys; // not important 36 | cin >> x[0] >> y[0] >> n; n++; 37 | for (int i = 1; i < n; i++) cin >> x[i] >> y[i]; 38 | for (int i = 0; i < n; i++) 39 | for (int j = i; j < n; j++) 40 | adj[i][j] = adj[j][i] = abs(x[i] - x[j]) + abs(y[i] - y[j]); 41 | memset(dp, -1, sizeof dp); 42 | // start from node 0 (bitmask = 00...01) 43 | cout << "The shortest path has length " << tsp(1, 0) << "\n"; 44 | } 45 | 46 | int main() { 47 | ios_base::sync_with_stdio(0); 48 | cin.tie(0); cout.tie(0); 49 | // freopen("input.txt", "r", stdin); 50 | // freopen("output.txt", "w", stdout); 51 | 52 | int tc; cin >> tc; 53 | for (int t = 1; t <= tc; t++) { 54 | // cout << "Case #" << t << ": "; 55 | solve(); 56 | } 57 | } -------------------------------------------------------------------------------- /Dynamic Programming/Weighted Job Scheduling.cpp: -------------------------------------------------------------------------------- 1 | // Given a list of jobs with start time, end time, and profit, find the maximum profit 2 | // Time complexity: O(nlogn) 3 | // Problem link: https://dunjudge.me/analysis/problems/414/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | 18 | 19 | void solve() { 20 | int n; cin >> n; 21 | ar arr[n]; 22 | for (int i = 0; i < n; i++) cin >> arr[i][1] >> arr[i][0] >> arr[i][2]; 23 | sort(arr, arr + n); // sort based on end time 24 | ll dp[n]; 25 | dp[0] = arr[0][2]; 26 | for (int i = 1; i < n; i++) { 27 | int k = lower_bound(arr, arr + n, ar{arr[i][1], 0, 0}) - arr - 1; 28 | if (k >= 0) 29 | dp[i] = max(dp[i - 1], dp[k] + arr[i][2]); 30 | else 31 | dp[i] = max(dp[i - 1], arr[i][2]); 32 | 33 | } 34 | cout << dp[n - 1] << "\n"; 35 | } 36 | 37 | int main() { 38 | ios_base::sync_with_stdio(0); 39 | cin.tie(0); cout.tie(0); 40 | // freopen("input.txt", "r", stdin); 41 | // freopen("output.txt", "w", stdout); 42 | 43 | int tc; tc = 1; 44 | for (int t = 1; t <= tc; t++) { 45 | // cout << "Case #" << t << ": "; 46 | solve(); 47 | } 48 | } -------------------------------------------------------------------------------- /Geometry/Basic.cpp: -------------------------------------------------------------------------------- 1 | // Basic geometry template for 2D Point (modified from kactl) 2 | // All other extended functions from kactl should still work normally 3 | // Problem link: https://cses.fi/problemset/task/2191/ (finding the area of a polygon) 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 5; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e9; 15 | 16 | template int sgn(T x) { return (x > 0) - (x < 0); } 17 | template struct Point { 18 | T x, y; 19 | Point() : x(0), y(0) {} 20 | Point(const T& x, const T& y) : x(x), y(y) {} 21 | 22 | friend std::ostream& operator<<(std::ostream& out, const Point& p) { return out << "(" << p.x << "," << p.y << ")"; } 23 | friend std::istream& operator>>(std::istream& in, Point& p) { return in >> p.x >> p.y; } 24 | 25 | friend bool operator==(const Point& a, const Point& b) { return tie(a.x, a.y) == tie(b.x, b.y); } 26 | friend bool operator!=(const Point& a, const Point& b) { return tie(a.x, a.y) != tie(b.x, b.y); } 27 | friend bool operator<(const Point& a, const Point& b) { return tie(a.x, a.y) < tie(b.x, b.y); } 28 | 29 | Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); } 30 | Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); } 31 | Point operator*(const T& d) const { return Point(x * d, y * d); } 32 | Point operator/(const T& d) const { return Point(x / d, y / d); } 33 | 34 | T dot(const Point& p) const { return x * p.x + y * p.y; } 35 | T cross(const Point& p) const { return x * p.y - y *p.x; } 36 | T cross(const Point& a, const Point& b) const { return (a - *this).cross(b - *this); } 37 | T dist2() const { return x * x + y * y; } 38 | double dist() const { return sqrt((double)dist2()); } 39 | double angle() const { return atan2(y, x); } // [-pi, pi] to x-axis 40 | 41 | Point unit() const { return *this / dist(); } // unit vector 42 | Point perp() const { return P(-y, x); } // rotates +90 degrees 43 | Point normal() const { return perp().unit(); } 44 | Point rotate(const double& a) const { return P(x*cos(a) - y*sin(a), x*sin(a) + y*cos(a)); } // ccw around (0,0) 45 | }; 46 | 47 | using pt = Point; 48 | 49 | template T polygonArea2(vector>& v) { 50 | T a = v.back().cross(v[0]); 51 | for (int i = 0; i < (int)v.size() - 1; i++) a += v[i].cross(v[i+1]); 52 | return a; 53 | } 54 | 55 | void solve() { 56 | int n; cin >> n; 57 | vector a(n); 58 | for (pt &p : a) cin >> p; 59 | cout << abs(polygonArea2(a)) << "\n"; 60 | } 61 | 62 | int main() { 63 | ios_base::sync_with_stdio(0); 64 | cin.tie(0); cout.tie(0); 65 | int tc = 1; 66 | // cin >> tc; 67 | for (int t = 1; t <= tc; t++) { 68 | // cout << "Case #" << t << ": "; 69 | solve(); 70 | } 71 | } -------------------------------------------------------------------------------- /Geometry/Sweep Line/Closest Pairs.cpp: -------------------------------------------------------------------------------- 1 | // Given n points (x, y) on a plane, find the minimum distance between a pair of points 2 | // Time complexity: (nlogn) 3 | // Problem link: https://vjudge.net/problem/UVA-10245 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e4 + 1; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e4; 15 | 16 | struct pt { 17 | double x, y; 18 | bool operator< (pt a) { // sort based on x 19 | return (x == a.x) ? y < a.y : x < a.x; 20 | } 21 | }; 22 | 23 | struct cmp { // custom comparator for set (sort based on y) 24 | bool operator() (pt a, pt b) { 25 | return (a.y == b.y) ? a.x < b.x : a.y < b.y; 26 | } 27 | }; 28 | 29 | void solve() { 30 | while (true) { 31 | int n; cin >> n; 32 | if (!n) return; 33 | 34 | pt pnts[n]; 35 | set box; 36 | for (int i = 0; i < n; i++) cin >> pnts[i].x >> pnts[i].y; 37 | sort(pnts, pnts + n); // sort bases on x-coordinates (from left to right) 38 | 39 | double ans = INF; 40 | /* Naive approach O(n^2) -> Searching through all pair of points 41 | for (int l = 0; l < n; l++) { 42 | for (int r = l + 1; r < n; r++) { 43 | if (pnts[r].second - pnts[l].second > ans) break; // this helps speed up the approach 44 | ans = min(ans, hypot(pnts[r].first - pnts[l].first, pnts[r].second - pnts[l].second)); 45 | } 46 | } 47 | */ 48 | box.clear(); 49 | box.insert(pnts[0]); 50 | for (int l = 0, r = 1; r < n; r++) { 51 | // removing leftmost points that will not contribute to the minimum distance 52 | while (l < r && pnts[r].x - pnts[l].x >= ans) 53 | box.erase(pnts[l++]); 54 | auto lo = box.lower_bound({pnts[r].x, pnts[r].y - ans}); 55 | auto hi = box.upper_bound({pnts[r].x, pnts[r].y + ans}); 56 | for (; lo != hi; lo++) 57 | ans = min(ans, hypot(pnts[r].x - lo->x, pnts[r].y - lo->y)); 58 | // A more succinct way to write 59 | // for (auto it = box.lower_bound({pnts[r].x - ans, pnts[r].y - ans}); it != box.end() && it->y - pnts[r].y <= ans; it++) 60 | // ans = min(ans, hypot(pnts[r].x - it->x, pnts[r].y - it->y)); 61 | box.insert(pnts[r]); 62 | } 63 | 64 | if (ans == INF) cout << "INFINITY\n"; 65 | else cout << fixed << setprecision(4) << ans << "\n"; 66 | } 67 | } 68 | 69 | int main() { 70 | ios_base::sync_with_stdio(0); 71 | cin.tie(0); cout.tie(0); 72 | int tc = 1; 73 | // cin >> tc; 74 | for (int t = 1; t <= tc; t++) { 75 | // cout << "Case #" << t << ": "; 76 | solve(); 77 | } 78 | } -------------------------------------------------------------------------------- /Geometry/Sweep Line/Rectangle Union.cpp: -------------------------------------------------------------------------------- 1 | // Given n rectangles on a plane (they are all parallel to the axis), find the union area of all the rectangles 2 | // Each rectangle is defined by two points (x1, y1) bottom left and (x2, y2) top right 3 | // Time complexity: O(n^2), can be improved to O(nlogn) 4 | // Problem link: https://cses.fi/problemset/task/1741/ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const l MOD = 1e9 + 7; 15 | const ll INF = 1e9; 16 | 17 | struct event { 18 | int id; // Index of rectangle in rects 19 | int type; // Type of event: 0 = Lower-left ; 1 = Upper-right 20 | event() {}; 21 | event(int id, int type) : id(id), type(type) {}; 22 | }; 23 | 24 | struct point{ 25 | int x, y; 26 | }; 27 | 28 | int n, e = 0; // n = no. of rectangles, e = no. of events 29 | point rects[MAX_N][2]; // Each rectangle consists of 2 points: [0] = lower-left ; [1] = upper-right 30 | event events_v [2 * MAX_N]; // Events of horizontal sweep line 31 | event events_h [2 * MAX_N]; // Events of vertical sweep line 32 | 33 | bool in_set[MAX_N] = {0}; // Boolean array in place of balanced binary tree (set) 34 | long long area = 0; // The output: Area of the union 35 | 36 | bool compare_x(event a, event b) { 37 | return rects[a.id][a.type].x < rects[b.id][b.type].x; 38 | } 39 | 40 | bool compare_y(event a, event b) { 41 | return rects[a.id][a.type].y < rects[b.id][b.type].y; 42 | } 43 | 44 | void solve() { 45 | cin >> n; 46 | for (int i = 0; i < n; i++){ 47 | cin >> rects[i][0].x >> rects[i][0].y; // Lower-left coordinate 48 | cin >> rects[i][1].x >> rects[i][1].y; // Upper-right coordinate 49 | events_v[e] = event(i, 0); 50 | events_h[e++] = event(i, 0); 51 | events_v[e] = event(i, 1); 52 | events_h[e++] = event(i, 1); 53 | } 54 | sort(events_v, events_v + e, compare_x); 55 | sort(events_h, events_h + e, compare_y); // Pre-sort set of horizontal edges 56 | in_set[events_v[0].id] = 1; 57 | 58 | // Vertical sweep line 59 | for (int i = 1; i < e; i++){ 60 | event cur = events_v[i], precur = events_v[i - 1]; 61 | int cnt = 0; // Counter to indicate how many rectangles are currently overlapping 62 | 63 | // Delta_x: Distance between current sweep line and previous sweep line 64 | ll delta_x = rects[cur.id][cur.type].x - rects[precur.id][precur.type].x; 65 | if (delta_x < 0) continue; 66 | 67 | int begin_y; 68 | // Horizontal sweep line 69 | for (int j = 0; j < e; j++){ 70 | if (in_set[events_h[j].id]){ 71 | if (events_h[j].type == 0) { 72 | if (cnt == 0) begin_y = rects[events_h[j].id][0].y; // Block starts 73 | cnt++; 74 | } 75 | else { 76 | cnt--; 77 | if (cnt == 0) { // Block ends 78 | ll delta_y = rects[events_h[j].id][1].y - begin_y; 79 | area += delta_x * delta_y; 80 | } 81 | } 82 | } 83 | } 84 | in_set[cur.id] = (cur.type == 0); 85 | } 86 | cout << area << "\n"; 87 | } 88 | 89 | int main() { 90 | ios_base::sync_with_stdio(0); 91 | cin.tie(0); cout.tie(0); 92 | // freopen("input.txt", "r", stdin); 93 | // freopen("output.txt", "w", stdout); 94 | 95 | int tc; tc = 1; 96 | for (int t = 1; t <= tc; t++) { 97 | // cout << "Case #" << t << ": "; 98 | solve(); 99 | } 100 | } -------------------------------------------------------------------------------- /Graphs/Graph Traversal/BFS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ar array 6 | #define ll long long 7 | 8 | const int MAX_N = 1e5 + 5; 9 | const ll MOD = 1e9 + 7; 10 | const ll INF = 1e9; 11 | 12 | int n, m; 13 | vector adj[MAX_N], dist; 14 | 15 | void bfs(int s) { 16 | dist.assign(n + 1, -1); 17 | queue q; 18 | dist[s] = 0; q.push(s); 19 | while (q.size()) { 20 | int u = q.front(); q.pop(); 21 | for (int v : adj[u]) { 22 | if (dist[v] == -1) { 23 | dist[v] = dist[u] + 1; 24 | q.push(v); 25 | } 26 | } 27 | } 28 | } 29 | 30 | void solve() { 31 | cin >> n >> m; 32 | for (int i = 0; i < m; i++) { 33 | int u, v; cin >> u >> v; 34 | adj[u].push_back(v); 35 | adj[v].push_back(u); 36 | } 37 | bfs(1); 38 | } 39 | 40 | int main() { 41 | ios_base::sync_with_stdio(0); 42 | cin.tie(0); cout.tie(0); 43 | // freopen("input.txt", "r", stdin); 44 | // freopen("output.txt", "w", stdout); 45 | 46 | int tc; tc = 1; 47 | for (int t = 1; t <= tc; t++) { 48 | // cout << "Case #" << t << ": "; 49 | solve(); 50 | } 51 | } -------------------------------------------------------------------------------- /Graphs/Graph Traversal/Bipartite.cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://cses.fi/problemset/task/1668 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 1e5 + 5; 11 | const ll MOD = 1e9 + 7; 12 | const ll INF = 1e9; 13 | 14 | int n, m, color[MAX_N]; 15 | vector adj[MAX_N]; 16 | 17 | void bfs(int s) { 18 | queue q; 19 | color[s] = 1; q.push(s); 20 | while (q.size()) { 21 | int u = q.front(); q.pop(); 22 | for (int v : adj[u]) { 23 | if (!color[v]) { 24 | color[v] = color[u] % 2 + 1; 25 | q.push(v); 26 | } 27 | else if (color[v] == color[u]) { 28 | cout << "IMPOSSIBLE\n"; 29 | exit(0); 30 | } 31 | } 32 | } 33 | } 34 | 35 | void solve() { 36 | cin >> n >> m; 37 | for (int i = 0; i < m; i++) { 38 | int u, v; cin >> u >> v; 39 | adj[u].push_back(v); 40 | adj[v].push_back(u); 41 | } 42 | for (int i = 1; i <= n; i++) 43 | if (!color[i]) 44 | bfs(i); 45 | for (int i = 1; i <= n; i++) 46 | cout << color[i] << " "; 47 | cout << "\n"; 48 | } 49 | 50 | int main() { 51 | ios_base::sync_with_stdio(0); 52 | cin.tie(0); cout.tie(0); 53 | int tc = 1; 54 | // cin >> tc; 55 | for (int t = 1; t <= tc; t++) { 56 | // cout << "Case #" << t << ": "; 57 | solve(); 58 | } 59 | } -------------------------------------------------------------------------------- /Graphs/Graph Traversal/DFS.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | #define ar array 6 | #define ll long long 7 | 8 | const int MAX_N = 1e5 + 5; 9 | const ll MOD = 1e9 + 7; 10 | const ll INF = 1e9; 11 | 12 | int n, m, vis[MAX_N]; 13 | vector adj[MAX_N]; 14 | 15 | void dfs(int u) { 16 | vis[u] = 1; 17 | for (int v : adj[u]) { 18 | if (vis[v]) continue; 19 | dfs(v); 20 | } 21 | } 22 | 23 | void solve() { 24 | cin >> n >> m; 25 | for (int i = 0; i < m; i++) { 26 | int u, v; cin >> u >> v; 27 | adj[u].push_back(v); 28 | adj[v].push_back(u); 29 | } 30 | for (int i = 1; i <= n; i++) { 31 | if (vis[i]) continue; 32 | dfs(i); 33 | } 34 | } 35 | 36 | int main() { 37 | ios_base::sync_with_stdio(0); 38 | cin.tie(0); cout.tie(0); 39 | int tc = 1; 40 | // cin >> tc; 41 | for (int t = 1; t <= tc; t++) { 42 | // cout << "Case #" << t << ": "; 43 | solve(); 44 | } 45 | } -------------------------------------------------------------------------------- /Graphs/Graph Traversal/Flood Fill.cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://cses.fi/problemset/task/1192 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 1e3 + 1; 11 | const int MOD = 1e9 + 7; 12 | const int INF = 1e9; 13 | const ll LINF = 1e18; 14 | 15 | int n, m, visited[MAX_N][MAX_N]; 16 | char grid[MAX_N][MAX_N]; 17 | 18 | const int di[] = {1, 0, -1, 0}; 19 | const int dj[] = {0, -1, 0, 1}; 20 | 21 | bool valid(int i, int j) { 22 | return i >= 0 && j >= 0 && i < n && j < m && grid[i][j] == '.'; 23 | } 24 | 25 | void dfs(int i, int j) { 26 | visited[i][j] = 1; 27 | for (int k = 0; k < 4; k++) { 28 | int ni = i + di[k], nj = j + dj[k]; 29 | if (valid(ni, nj) && !visited[ni][nj]) { 30 | dfs(ni, nj); 31 | } 32 | } 33 | } 34 | 35 | void solve() { 36 | cin >> n >> m; 37 | for (int i = 0; i < n; i++) 38 | for (int j = 0; j < m; j++) 39 | cin >> grid[i][j]; 40 | 41 | int ans = 0; 42 | for (int i = 0; i < n; i++) { 43 | for (int j = 0; j < m; j++) { 44 | if (valid(i, j) && !visited[i][j]) { 45 | dfs(i, j); 46 | ans++; 47 | } 48 | } 49 | } 50 | cout << ans << "\n"; 51 | } 52 | 53 | int main() { 54 | ios_base::sync_with_stdio(0); 55 | cin.tie(0); cout.tie(0); 56 | // freopen("input.txt", "r", stdin); 57 | // freopen("output.txt", "w", stdout); 58 | 59 | int tc; tc = 1; 60 | for (int t = 1; t <= tc; t++) { 61 | // cout << "Case #" << t << ": "; 62 | solve(); 63 | } 64 | } -------------------------------------------------------------------------------- /Graphs/Lowest Common Ancestor/LCA (Binary Lifting).cpp: -------------------------------------------------------------------------------- 1 | // Time complexity: O(nlogn) build, O(logn) per query 2 | // Problem link: https://cses.fi/problemset/task/1688 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2e5 + 1; 12 | const ll MOD = 1e9 + 7; 13 | const ll INF = 1e9; 14 | 15 | const int MAX_L = 20; 16 | 17 | int n, q, par[MAX_N][MAX_L], dep[MAX_N]; 18 | vector adj[MAX_N]; 19 | 20 | void dfs(int u, int p = 0) { 21 | par[u][0] = p; 22 | for (int i = 1; i < MAX_L; i++) 23 | par[u][i] = par[par[u][i - 1]][i - 1]; 24 | for (int v : adj[u]) { 25 | if (v == p) continue; 26 | dep[v] = dep[u] + 1; 27 | dfs(v, u); 28 | } 29 | } 30 | 31 | int ancestor(int u, int k) { 32 | for (int i = 0; i < MAX_L; i++) 33 | if (k & (1 << i)) 34 | u = par[u][i]; 35 | return u; 36 | } 37 | 38 | int lca(int u, int v) { 39 | if (dep[u] < dep[v]) swap(u, v); 40 | u = ancestor(u, dep[u] - dep[v]); 41 | if (u == v) return u; 42 | for (int i = MAX_L - 1; i >= 0; i--) 43 | if (par[u][i] != par[v][i]) 44 | u = par[u][i], v = par[v][i]; 45 | return par[u][0]; 46 | } 47 | 48 | void solve() { 49 | cin >> n >> q; 50 | for (int v = 2; v <= n; v++) { 51 | int u; cin >> u; 52 | adj[u].push_back(v); 53 | adj[v].push_back(u); 54 | } 55 | dfs(1); 56 | while (q--) { 57 | int u, v; cin >> u >> v; 58 | cout << lca(u, v) << "\n"; 59 | } 60 | } 61 | 62 | int main() { 63 | ios_base::sync_with_stdio(0); 64 | cin.tie(0); cout.tie(0); 65 | int tc = 1; 66 | // cin >> tc; 67 | for (int t = 1; t <= tc; t++) { 68 | // cout << "Case #" << t << ": "; 69 | solve(); 70 | } 71 | } -------------------------------------------------------------------------------- /Graphs/Lowest Common Ancestor/LCA (RMQ).cpp: -------------------------------------------------------------------------------- 1 | // Convert the Lowest Common Ancestor (LCA) problem into the Range Minimum Query (RMQ) Problem 2 | // RMQ can be solved using Sparse Table 3 | // Time complexity: O(nlogn) build, O(1) per query 4 | // Problem link: https://cses.fi/problemset/task/1688 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 2e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | const int MAX_L = 30; 19 | 20 | int n, q, idx; 21 | int dep[2 * MAX_N], euler[2 * MAX_N], first[MAX_N], lg[2 * MAX_N]; 22 | ar dp[2 * MAX_N][MAX_L]; // need to store both the indices and the min value 23 | vector adj[MAX_N]; 24 | 25 | void dfs(int u, int p = 0, int h = 0) { 26 | euler[++idx] = u; 27 | dep[idx] = h; 28 | first[u] = idx; 29 | for (int v : adj[u]) { 30 | if (v != p) { 31 | dfs(v, u, h + 1); 32 | euler[++idx] = u; 33 | dep[idx] = h; 34 | } 35 | } 36 | } 37 | 38 | void build_lg_table() { 39 | lg[1] = 0; 40 | for (int i = 2; i <= 2 * n; i++) 41 | lg[i] = lg[i / 2] + 1; 42 | } 43 | 44 | void build_sparse_table() { 45 | for (int i = 1; i <= 2 * n; i++) 46 | dp[i][0] = {dep[i], euler[i]}; 47 | for (int j = 1; j < MAX_L; j++) 48 | for (int i = 1; i + (1 << j) <= 2 * (n + 1); i++) 49 | dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]); 50 | } 51 | 52 | int min_query(int l, int r) { 53 | int k = lg[r - l + 1]; 54 | return min(dp[l][k], dp[r - (1 << k) + 1][k])[1]; // return the index with min value 55 | } 56 | 57 | int lca(int u, int v) { 58 | int l = first[u], r = first[v]; 59 | if (l > r) swap(l, r); 60 | return min_query(l, r); 61 | } 62 | 63 | void solve() { 64 | cin >> n >> q; 65 | for (int v = 2; v <= n; v++) { 66 | int u; cin >> u; 67 | adj[u].push_back(v); 68 | } 69 | dfs(1); 70 | build_lg_table(); 71 | build_sparse_table(); 72 | while (q--) { 73 | int a, b; cin >> a >> b; 74 | cout << lca(a, b) << "\n"; 75 | } 76 | cout << "\n"; 77 | } 78 | 79 | int main() { 80 | ios_base::sync_with_stdio(0); 81 | cin.tie(0); cout.tie(0); 82 | // freopen("input.txt", "r", stdin); 83 | // freopen("output.txt", "w", stdout); 84 | 85 | int tc; tc = 1; 86 | for (int t = 1; t <= tc; t++) { 87 | // cout << "Case #" << t << ": "; 88 | solve(); 89 | } 90 | } -------------------------------------------------------------------------------- /Graphs/Lowest Common Ancestor/README.md: -------------------------------------------------------------------------------- 1 | ## Some key points to take note of: 2 | - Both methods have the same time complexity, but Binary Lifting is simpler to code. 3 | - The idea of Binary Lifting (storing the 2^K ancestors of each node) can be useful in many other problems 4 | -------------------------------------------------------------------------------- /Graphs/Max Flow/Dinic.cpp: -------------------------------------------------------------------------------- 1 | // Maximum Flow (Dinic Algorithm) 2 | // Time complexity: O(n^2m) 3 | // A slight improvement from Edmonds_Karp Algorithm 4 | // Problem link: https://cses.fi/problemset/task/1694/ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 5; 14 | const ll MOD = 1e9 + 7; 15 | const ll INF = 1e18; 16 | 17 | struct max_flow_graph { 18 | struct edge { 19 | int u, v, cap, flow; 20 | }; 21 | int n; 22 | vector el; 23 | vector> adj; 24 | vector dist, par; 25 | max_flow_graph(int n) : n(n), adj(n) {} 26 | void add_edge(int u, int v, int w) { 27 | adj[u].push_back(el.size()); 28 | el.push_back({u, v, w, 0}); 29 | adj[v].push_back(el.size()); 30 | el.push_back({v, u, 0, 0}); 31 | } 32 | int send_one_flow(int s, int e) { 33 | int nf = INF; 34 | for (int u = e; u != s; u = el[par[u]].u) { 35 | nf = min(nf, el[par[u]].cap - el[par[u]].flow); 36 | } 37 | for (int u = e; u != s; u = el[par[u]].u) { 38 | el[par[u]].flow += nf; 39 | el[par[u]^1].flow -= nf; 40 | } 41 | return nf; 42 | } 43 | bool bfs(int s, int e) { 44 | dist.assign(n, INF); 45 | par.assign(n, 0); 46 | queue q; 47 | q.push(s); dist[s] = 0; 48 | while (q.size()) { 49 | int u = q.front(); q.pop(); 50 | if (u == e) break; 51 | for (int idx : adj[u]) { 52 | if (el[idx].cap > el[idx].flow && dist[el[idx].v] > dist[el[idx].u] + 1) { 53 | dist[el[idx].v] = dist[el[idx].u] + 1; 54 | par[el[idx].v] = idx; 55 | q.push(el[idx].v); 56 | } 57 | } 58 | } 59 | return dist[e] < INF; 60 | } 61 | int dfs(int s, int e, int f = INF) { 62 | if (s == e || f == 0) return f; 63 | for (int idx : adj[s]) { 64 | if (dist[el[idx].v] != dist[s] + 1) continue; 65 | if (int nf = dfs(el[idx].v, e, min(f, el[idx].cap - el[idx].flow))) { 66 | el[idx].flow += nf; 67 | el[idx^1].flow -= nf; 68 | return nf; 69 | } 70 | } 71 | return 0; 72 | } 73 | ll dinic(int s, int e) { 74 | ll mf = 0; 75 | while (bfs(s, e)) { 76 | while (int nf = dfs(s, e)) mf += nf; 77 | } 78 | return mf; 79 | } 80 | }; 81 | 82 | void solve() { 83 | int n, m; cin >> n >> m; 84 | max_flow_graph adj(n); 85 | for (int i = 0; i < m; i++) { 86 | int u, v, w; cin >> u >> v >> w; u--; v--; 87 | adj.add_edge(u, v, w); 88 | } 89 | cout << adj.dinic(0, n - 1) << "\n"; 90 | } 91 | 92 | int main() { 93 | ios_base::sync_with_stdio(0); 94 | cin.tie(0); cout.tie(0); 95 | int tc = 1; 96 | // cin >> tc; 97 | for (int t = 1; t <= tc; t++) { 98 | // cout << "Case #" << t << ": "; 99 | solve(); 100 | } 101 | } -------------------------------------------------------------------------------- /Graphs/Max Flow/Edmonds_Karp.cpp: -------------------------------------------------------------------------------- 1 | // Maximum Flow (Dinic Algorithm) 2 | // Time complexity: O(n^2m) 3 | // A slight improvement from Edmonds_Karp Algorithm 4 | // Problem link: https://cses.fi/problemset/task/1694/ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 5; 14 | const ll MOD = 1e9 + 7; 15 | const ll INF = 1e18; 16 | 17 | struct max_flow_graph { 18 | struct edge { 19 | int u, v, cap, flow; 20 | }; 21 | int n; 22 | vector el; 23 | vector> adj; 24 | vector dist, par; 25 | max_flow_graph(int n) : n(n), adj(n) {} 26 | void add_edge(int u, int v, int w) { 27 | adj[u].push_back(el.size()); 28 | el.push_back({u, v, w, 0}); 29 | adj[v].push_back(el.size()); 30 | el.push_back({v, u, 0, 0}); 31 | } 32 | int send_one_flow(int s, int e) { 33 | int nf = INF; 34 | for (int u = e; u != s; u = el[par[u]].u) { 35 | nf = min(nf, el[par[u]].cap - el[par[u]].flow); 36 | } 37 | for (int u = e; u != s; u = el[par[u]].u) { 38 | el[par[u]].flow += nf; 39 | el[par[u]^1].flow -= nf; 40 | } 41 | return nf; 42 | } 43 | bool bfs(int s, int e) { 44 | dist.assign(n, INF); 45 | par.assign(n, 0); 46 | queue q; 47 | q.push(s); dist[s] = 0; 48 | while (q.size()) { 49 | int u = q.front(); q.pop(); 50 | if (u == e) break; 51 | for (int idx : adj[u]) { 52 | if (el[idx].cap > el[idx].flow && dist[el[idx].v] > dist[el[idx].u] + 1) { 53 | dist[el[idx].v] = dist[el[idx].u] + 1; 54 | par[el[idx].v] = idx; 55 | q.push(el[idx].v); 56 | } 57 | } 58 | } 59 | return dist[e] < INF; 60 | } 61 | ll edmonds_karp(int s, int e) { 62 | ll mf = 0; 63 | while (bfs(s, e)) mf += send_one_flow(s, e); 64 | return mf; 65 | } 66 | }; 67 | 68 | void solve() { 69 | int n, m; cin >> n >> m; 70 | max_flow_graph adj(n); 71 | for (int i = 0; i < m; i++) { 72 | int u, v, w; cin >> u >> v >> w; u--; v--; 73 | adj.add_edge(u, v, w); 74 | } 75 | cout << adj.edmonds_karp(0, n - 1) << "\n"; 76 | } 77 | 78 | int main() { 79 | ios_base::sync_with_stdio(0); 80 | cin.tie(0); cout.tie(0); 81 | int tc = 1; 82 | // cin >> tc; 83 | for (int t = 1; t <= tc; t++) { 84 | // cout << "Case #" << t << ": "; 85 | solve(); 86 | } 87 | } -------------------------------------------------------------------------------- /Graphs/Minimum Spanning Tree/Kruskal.cpp: -------------------------------------------------------------------------------- 1 | // Need to use edge list for Kruskal 2 | // Time Complexity: O(mlogn) 3 | // Problem link: https://cses.fi/problemset/task/1675 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | int n, m, par[MAX_N]; 18 | vector> edges; 19 | 20 | int find(int u) { 21 | return u == par[u] ? u : par[u] = find(par[u]); 22 | } 23 | 24 | void unite(int u, int v) { 25 | par[find(u)] = find(v); 26 | } 27 | 28 | void kruskal() { 29 | sort(edges.begin(), edges.end()); 30 | for (int i = 1; i <= n; i++) par[i] = i; 31 | 32 | ll cnt = 0, cost = 0; 33 | for (auto [w, u, v] : edges) { 34 | u = find(u), v = find(v); 35 | if (u != v) { 36 | par[u] = v; 37 | cost += w; 38 | cnt++; 39 | } 40 | } 41 | if (cnt == n - 1) cout << cost << "\n"; 42 | else cout << "IMPOSSIBLE\n"; 43 | } 44 | 45 | void solve() { 46 | cin >> n >> m; 47 | for (int i = 0; i < m; i++) { 48 | int u, v, w; cin >> u >> v >> w; 49 | edges.push_back({w, u, v}); 50 | } 51 | kruskal(); 52 | } 53 | 54 | int main() { 55 | ios_base::sync_with_stdio(0); 56 | cin.tie(0); cout.tie(0); 57 | // freopen("input.txt", "r", stdin); 58 | // freopen("output.txt", "w", stdout); 59 | 60 | int tc; tc = 1; 61 | for (int t = 1; t <= tc; t++) { 62 | // cout << "Case #" << t << ": "; 63 | solve(); 64 | } 65 | } -------------------------------------------------------------------------------- /Graphs/Minimum Spanning Tree/Prim.cpp: -------------------------------------------------------------------------------- 1 | // Prim Agorithm is similar to Dijkstra 2 | // Time Complexity: O(mlogn) 3 | // Problem link: https://cses.fi/problemset/task/1675 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | int n, m, visited[MAX_N]; 18 | vector> adj[MAX_N]; 19 | 20 | void prim(int s = 1) { 21 | ll cost = 0; 22 | priority_queue, vector>, greater>> pq; 23 | visited[s] = 1; 24 | for (auto [u, d] : adj[s]) 25 | if (!visited[u]) 26 | pq.push({d, u}); 27 | while (pq.size()) { 28 | auto [d, u] = pq.top(); pq.pop(); 29 | if (!visited[u]) { 30 | cost += d; 31 | visited[u] = 1; 32 | for (auto [v, w] : adj[u]) 33 | if (!visited[v]) 34 | pq.push({w, v}); 35 | } 36 | } 37 | for (int i = 1; i <= n; i++) { 38 | if (!visited[i]) { 39 | cout << "IMPOSSIBLE\n"; 40 | exit(0); 41 | } 42 | } 43 | cout << cost << "\n"; 44 | } 45 | 46 | void solve() { 47 | cin >> n >> m; 48 | for(int i = 0; i < m; i++) { 49 | int u, v, w; cin >> u >> v >> w; 50 | adj[u].push_back({v, w}); 51 | adj[v].push_back({u, w}); 52 | } 53 | prim(); 54 | } 55 | 56 | int main() { 57 | ios_base::sync_with_stdio(0); 58 | cin.tie(0); cout.tie(0); 59 | // freopen("input.txt", "r", stdin); 60 | // freopen("output.txt", "w", stdout); 61 | 62 | int tc; tc = 1; 63 | for (int t = 1; t <= tc; t++) { 64 | // cout << "Case #" << t << ": "; 65 | solve(); 66 | } 67 | } -------------------------------------------------------------------------------- /Graphs/Minimum Spanning Tree/README.md: -------------------------------------------------------------------------------- 1 | ## Some key points to take note of: 2 | - If the graph is **dense** (i.e Euclidean Minimum Spanning Tree where **n = m^2**), use Prim since it is **faster** than Kruskal 3 | - Otherwise, use Kruskal since it is **simpler** to code 4 | -------------------------------------------------------------------------------- /Graphs/Shortest Paths/0-1 BFS.cpp: -------------------------------------------------------------------------------- 1 | // 0-1 BFS for SSSP 2 | // Idea: same as normal BFS, but now when processing neighbours of a node, there are 2 cases: 3 | // 1) Push the node to the front of the queue (To push a node with same level - 0 edge) 4 | // 2) Push the node to the back of the queue (To push a node on next level - 1 edge) 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | int n, m; 19 | vector> adj[MAX_N]; 20 | vector dist; 21 | 22 | void bfs(int s) { 23 | dist.assign(n + 1, -1); 24 | deque q; 25 | dist[s] = 0; q.push_front(s); 26 | while (q.size()) { 27 | int u = q.front(); q.pop_front(); 28 | for (auto [v, w] : adj[u]) { 29 | if (dist[v] == -1) { 30 | dist[v] = dist[u] + w; 31 | if (w == 1) q.push_back(v); 32 | else q.push_front(v); 33 | } 34 | } 35 | } 36 | } 37 | 38 | void solve() { 39 | cin >> n >> m; 40 | for (int i = 0; i < m; i++) { 41 | int u, v, w; cin >> u >> v >> w; // w is 0 or 1 42 | adj[u].push_back({v, w}); 43 | adj[v].push_back({u, w}); 44 | } 45 | bfs(1); 46 | for (int i = 1; i <= n; i++) 47 | cout << dist[i] << " "; 48 | cout << "\n"; 49 | 50 | /* 51 | Example input: 52 | 6 5 53 | 1 2 0 54 | 5 1 1 55 | 2 4 1 56 | 4 6 1 57 | 1 4 0 58 | Expected output: 59 | 0 0 -1 0 1 1 60 | */ 61 | } 62 | 63 | int main() { 64 | ios_base::sync_with_stdio(0); 65 | cin.tie(0); cout.tie(0); 66 | // freopen("input.txt", "r", stdin); 67 | // freopen("output.txt", "w", stdout); 68 | 69 | int tc; tc = 1; 70 | for (int t = 1; t <= tc; t++) { 71 | // cout << "Case #" << t << ": "; 72 | solve(); 73 | } 74 | } -------------------------------------------------------------------------------- /Graphs/Shortest Paths/Bellman_Ford.cpp: -------------------------------------------------------------------------------- 1 | // Time complexity: O(nm) 2 | // Problem link: https://cses.fi/problemset/task/1197/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 2.5e3 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e15; 15 | 16 | int n, m, par[MAX_N]; 17 | vector> adj[MAX_N]; 18 | vector dist; 19 | 20 | void bellman_ford(int s) { 21 | dist.assign(n + 1, LINF); 22 | dist[s] = 0; 23 | for (int i = 0; i < n - 1; i++) { 24 | for (int u = 1; u <= n; u++) { 25 | for (auto [v, w] : adj[u]) { 26 | if (dist[u] + w < dist[v]) { 27 | par[v] = u; 28 | dist[v] = dist[u] + w; 29 | } 30 | } 31 | } 32 | } 33 | } 34 | 35 | void cycle_detect() { 36 | int cycle = 0; 37 | for (int u = 1; u <= n; u++) { 38 | for (auto [v, w] : adj[u]) { 39 | if (dist[u] + w < dist[v]) { 40 | cycle = v; 41 | break; 42 | } 43 | } 44 | } 45 | if (!cycle) cout << "NO\n"; 46 | else { 47 | cout << "YES\n"; 48 | // backtrack to print the cycle 49 | for (int i = 0; i < n; i++) cycle = par[cycle]; 50 | vector ans; ans.push_back(cycle); 51 | for (int i = par[cycle]; i != cycle; i = par[i]) ans.push_back(i); 52 | ans.push_back(cycle); 53 | reverse(ans.begin(), ans.end()); 54 | for (int x : ans) cout << x << " "; 55 | cout << "\n"; 56 | } 57 | } 58 | 59 | void solve() { 60 | cin >> n >> m; 61 | for (int i = 0; i < m; i++) { 62 | int u, v, w; cin >> u >> v >> w; 63 | adj[u].push_back({v, w}); 64 | } 65 | bellman_ford(1); 66 | cycle_detect(); 67 | } 68 | 69 | int main() { 70 | ios_base::sync_with_stdio(0); 71 | cin.tie(0); cout.tie(0); 72 | // freopen("input.txt", "r", stdin); 73 | // freopen("output.txt", "w", stdout); 74 | 75 | int tc; tc = 1; 76 | for (int t = 1; t <= tc; t++) { 77 | // cout << "Case #" << t << ": "; 78 | solve(); 79 | } 80 | } -------------------------------------------------------------------------------- /Graphs/Shortest Paths/Dijkstra.cpp: -------------------------------------------------------------------------------- 1 | // Time complexity: O(n + mlogn) 2 | // Problem link: https://cses.fi/problemset/task/1671 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e15; 15 | 16 | int n, m; 17 | vector> adj[MAX_N]; 18 | vector dist; 19 | 20 | void dijkstra(int s) { 21 | dist.assign(n + 1, LINF); 22 | priority_queue, vector>, greater>> pq; 23 | dist[s] = 0; pq.push({0, s}); 24 | while (pq.size()) { 25 | auto [d, u] = pq.top(); pq.pop(); 26 | if (d > dist[u]) continue; 27 | for (auto [v, w] : adj[u]) { 28 | if (dist[v] > dist[u] + w) { 29 | dist[v] = dist[u] + w; 30 | pq.push({dist[v], v}); 31 | } 32 | } 33 | } 34 | } 35 | 36 | void solve() { 37 | cin >> n >> m; 38 | for (int i = 0; i < m; i++) { 39 | int u, v, w; cin >> u >> v >> w; 40 | adj[u].push_back({v, w}); 41 | } 42 | dijkstra(1); 43 | for (int i = 1; i <= n; i++) cout << dist[i] << " "; 44 | cout << "\n"; 45 | } 46 | 47 | int main() { 48 | ios_base::sync_with_stdio(0); 49 | cin.tie(0); cout.tie(0); 50 | // freopen("input.txt", "r", stdin); 51 | // freopen("output.txt", "w", stdout); 52 | 53 | int tc; tc = 1; 54 | for (int t = 1; t <= tc; t++) { 55 | // cout << "Case #" << t << ": "; 56 | solve(); 57 | } 58 | } -------------------------------------------------------------------------------- /Graphs/Shortest Paths/Floyd_Warshall.cpp: -------------------------------------------------------------------------------- 1 | // Find all pair shortest paths 2 | // Time complexity: O(n^3) 3 | // Problem link: https://cses.fi/problemset/task/1672 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 500 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e15; 16 | 17 | int n, m, q; 18 | ll dist[MAX_N][MAX_N]; 19 | 20 | void floyd_warshall() { // 4 lines 21 | for (int k = 1; k <= n; k++) 22 | for (int i = 1; i <= n; i++) 23 | for (int j = 1; j <= n; j++) 24 | dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]); 25 | } 26 | 27 | void solve() { 28 | cin >> n >> m >> q; 29 | for (int i = 1; i <= n; i++) 30 | for (int j = 1; j <= n; j++) 31 | dist[i][j] = (i == j) ? 0 : LINF; 32 | for (int i = 0; i < m; i++) { 33 | int u, v, w; cin >> u >> v >> w; 34 | dist[u][v] = dist[v][u] = min(dist[u][v], (ll)w); 35 | } 36 | floyd_warshall(); 37 | while (q--) { 38 | int u, v; cin >> u >> v; 39 | cout << (dist[u][v] < LINF ? dist[u][v] : -1) << "\n"; 40 | } 41 | } 42 | 43 | int main() { 44 | ios_base::sync_with_stdio(0); 45 | cin.tie(0); cout.tie(0); 46 | // freopen("input.txt", "r", stdin); 47 | // freopen("output.txt", "w", stdout); 48 | 49 | int tc; tc = 1; 50 | for (int t = 1; t <= tc; t++) { 51 | // cout << "Case #" << t << ": "; 52 | solve(); 53 | } 54 | } -------------------------------------------------------------------------------- /Graphs/Shortest Paths/README.md: -------------------------------------------------------------------------------- 1 | ## Some key points to take note of: 2 | - If the graph is **unweighted**, a simple if BFS can be used instead of Dijkstra 3 | - If the graph has only **2 values of weights** (i.e 0 and 1), a BFS with deque implementation can also be used (this is called **0-1 BFS**) 4 | - For BFS and Dijkstra, the problem of **Single-Source Shortest Path** can be extended into **Multi-Source Shortest Path** by pushing all the starting nodes into the queue/priority queue at the beginning and relax the neighbouring edges as normal 5 | -------------------------------------------------------------------------------- /Graphs/Strongly Connected Components (SSCs)/Advanced example.cpp: -------------------------------------------------------------------------------- 1 | // Create a new graph by merging all nodes in a SCC into a single node, then DP 2 | // Problem link: https://cses.fi/problemset/task/1686/ 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, m, scc, arr[MAX_N], comp[MAX_N], visited[MAX_N]; 17 | ll new_arr[MAX_N], dp[MAX_N]; 18 | vector adj[2][MAX_N], new_adj[MAX_N], dfn; 19 | 20 | void dfs(int u, int t) { 21 | visited[u] = 1; 22 | if (t == 1) { 23 | comp[u] = scc; 24 | new_arr[scc] += arr[u]; 25 | } 26 | for (int v : adj[t][u]) { 27 | if (!visited[v]) { 28 | dfs(v, t); 29 | } 30 | } 31 | if (t == 0) dfn.push_back(u); 32 | } 33 | 34 | void kosaraju() { 35 | for (int i = 1; i <= n; i++) { 36 | if (!visited[i]) { 37 | dfs(i, 0); 38 | } 39 | } 40 | memset(visited, 0, sizeof visited); 41 | for (int i = n - 1; i >= 0; i--) { 42 | if (!visited[dfn[i]]) { 43 | scc++; 44 | dfs(dfn[i], 1); 45 | } 46 | } 47 | } 48 | 49 | ll dfs2(int u) { 50 | ll res = 0; 51 | for (int v : new_adj[u]) { 52 | if (!dp[v]) dfs2(v); 53 | res = max(res, dp[v]); 54 | } 55 | return dp[u] = res + new_arr[u]; 56 | } 57 | 58 | void solve() { 59 | cin >> n >> m; 60 | for (int i = 1; i <= n; i++) cin >> arr[i]; 61 | for (int i = 0; i < m; i++) { 62 | int u, v; cin >> u >> v; 63 | adj[0][u].push_back(v); 64 | adj[1][v].push_back(u); 65 | } 66 | kosaraju(); 67 | // merging nodes in a SCC 68 | for (int u = 1; u <= n; u++) 69 | for (int v : adj[0][u]) 70 | if (comp[u] != comp[v]) 71 | new_adj[comp[u]].push_back(comp[v]); 72 | // DP on the new graph 73 | ll ans = 0; 74 | for (int i = 1; i <= scc; i++) 75 | ans = max(ans, dfs2(i)); 76 | cout << ans << "\n"; 77 | } 78 | 79 | int main() { 80 | ios_base::sync_with_stdio(0); 81 | cin.tie(0); cout.tie(0); 82 | // freopen("input.txt", "r", stdin); 83 | // freopen("output.txt", "w", stdout); 84 | 85 | int tc; tc = 1; 86 | for (int t = 1; t <= tc; t++) { 87 | // cout << "Case #" << t << ": "; 88 | solve(); 89 | } 90 | } -------------------------------------------------------------------------------- /Graphs/Strongly Connected Components (SSCs)/Bridges&ArticulationPoints.cpp: -------------------------------------------------------------------------------- 1 | // Given an undirected graph, find all bridges and articulation points 2 | // Perform a DFS to form a DFS spanning tree 3 | // u-v is a bridge <=> there is a back edge connecting a descendant of v and an ancestor of u 4 | // Time complexity: O(n + m) 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | // dfs_num[u] stores the iteration counter when DFS visits node u for the 1st time 19 | // dfs_low[u] stores the lowest dfs_num reachable from the current DFS spanning subtree of node u 20 | // dfs_low[u] can only be made smaller if there is a back edge to form a cycle and v is currently visited 21 | 22 | int n, m, dfsCounter; 23 | int dfs_num[MAX_N], dfs_low[MAX_N], visited[MAX_N]; 24 | vector adj[MAX_N]; 25 | 26 | void dfs(int u, int p = -1) { 27 | dfs_num[u] = dfs_low[u] = dfsCounter++; 28 | visited[u] = 1; 29 | int num_child = 0; 30 | for (int v : adj[u]) { 31 | if (v == p) continue; 32 | // back edge 33 | if (visited[v]) dfs_low[u] = min(dfs_low[u], dfs_num[v]); 34 | // tree edge 35 | else { 36 | dfs(v, u); 37 | dfs_low[u] = min(dfs_low[u], dfs_low[v]); 38 | num_child++; 39 | if (dfs_low[v] > dfs_num[u]) 40 | cout << "Edge " << u << "-" << v << " is a bridge\n"; 41 | if (dfs_low[v] >= dfs_num[u] && p != -1) 42 | cout << "Node " << u << " is an articulation point\n"; 43 | } 44 | } 45 | // special case: the root node is an articulation point if it has more than 1 child 46 | if (p == -1 && num_child > 1) 47 | cout << "Node " << u << " is an articulation point\n"; 48 | } 49 | 50 | void solve() { 51 | cin >> n >> m; 52 | for (int i = 0; i < m; i++) { 53 | int u, v; cin >> u >> v; 54 | adj[u].push_back(v); 55 | adj[v].push_back(u); 56 | } 57 | memset(dfs_low, -1, sizeof dfs_low); 58 | memset(dfs_num, -1, sizeof dfs_num); 59 | for (int i = 1; i <= n; i++) 60 | if (!visited[i]) 61 | dfs(i); 62 | 63 | /* 64 | Example input: 65 | 12 16 66 | 1 3 67 | 3 5 68 | 5 7 69 | 3 7 70 | 3 8 71 | 1 5 72 | 1 6 73 | 3 6 74 | 6 2 75 | 2 8 76 | 2 4 77 | 4 10 78 | 1 9 79 | 9 11 80 | 11 12 81 | 9 12 82 | 83 | Expected output: 84 | Edge 4-10 is a bridge 85 | Node 4 is an articulation point 86 | Edge 2-4 is a bridge 87 | Node 2 is an articulation point 88 | Node 9 is an articulation point 89 | Edge 1-9 is a bridge 90 | Node 1 is an articulation point 91 | */ 92 | } 93 | 94 | int main() { 95 | ios_base::sync_with_stdio(0); 96 | cin.tie(0); cout.tie(0); 97 | // freopen("input.txt", "r", stdin); 98 | // freopen("output.txt", "w", stdout); 99 | 100 | int tc; tc = 1; 101 | for (int t = 1; t <= tc; t++) { 102 | // cout << "Case #" << t << ": "; 103 | solve(); 104 | } 105 | } -------------------------------------------------------------------------------- /Graphs/Strongly Connected Components (SSCs)/Kosaraju.cpp: -------------------------------------------------------------------------------- 1 | // Kosaraju's algorithm to find strongly connected components (SCCs) by running DFS twice 2 | // 1st pass done on the original graph and record the topological order of the nodes 3 | // 2nd pass done on the transposed graph using the order found in the 1st pass 4 | // Time complexity: O(n + m) 5 | // Problem link: https://cses.fi/problemset/task/1682/ 6 | 7 | #include 8 | 9 | using namespace std; 10 | 11 | #define ar array 12 | #define ll long long 13 | 14 | const int MAX_N = 1e5 + 1; 15 | const int MOD = 1e9 + 7; 16 | const int INF = 1e9; 17 | const ll LINF = 1e18; 18 | 19 | int n, m, scc, visited[MAX_N]; 20 | vector adj[2][MAX_N], comp[MAX_N], dfn; 21 | // adj[0] is the original graph, adj[1] is the transposed graph 22 | 23 | // t = 0 means 1st pass, t = 1 means 2nd pass 24 | void dfs(int u, int t) { 25 | visited[u] = 1; 26 | if (t == 1) comp[scc].push_back(u); 27 | for (int v : adj[t][u]) { 28 | if (!visited[v]) { 29 | dfs(v, t); 30 | } 31 | } 32 | if (t == 0) dfn.push_back(u); 33 | } 34 | 35 | void kosaraju() { 36 | for (int i = 1; i <= n; i++) { 37 | if (!visited[i]) { 38 | dfs(i, 0); 39 | } 40 | } 41 | memset(visited, 0, sizeof visited); 42 | for (int i = n - 1; i >= 0; i--) { 43 | if (!visited[dfn[i]]) { 44 | scc++; 45 | dfs(dfn[i], 1); 46 | } 47 | } 48 | } 49 | 50 | void solve() { 51 | cin >> n >> m; 52 | for (int i = 0; i < m; i++) { 53 | int u, v; cin >> u >> v; 54 | adj[0][u].push_back(v); 55 | adj[1][v].push_back(u); 56 | } 57 | kosaraju(); 58 | if (scc == 1) cout << "YES\n"; 59 | else { 60 | cout << "NO\n"; 61 | memset(visited, 0, sizeof visited); 62 | dfs(comp[1][0], 0); 63 | if (!visited[comp[2][0]]) 64 | cout << comp[1][0] << " " << comp[2][0] << "\n"; 65 | else 66 | cout << comp[2][0] << " " << comp[1][0] << "\n"; 67 | } 68 | } 69 | 70 | int main() { 71 | ios_base::sync_with_stdio(0); 72 | cin.tie(0); cout.tie(0); 73 | // freopen("input.txt", "r", stdin); 74 | // freopen("output.txt", "w", stdout); 75 | 76 | int tc; tc = 1; 77 | for (int t = 1; t <= tc; t++) { 78 | // cout << "Case #" << t << ": "; 79 | solve(); 80 | } 81 | } -------------------------------------------------------------------------------- /Graphs/Strongly Connected Components (SSCs)/Tarjan.cpp: -------------------------------------------------------------------------------- 1 | // Tarjan's algorithm to find strongly connected components (SCCs) 2 | // SSCs form subtrees in the DFS spanning tree 3 | // Time complexity: O(n + m) 4 | // Problem link: https://cses.fi/problemset/task/1682/ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | // dfs_num[u] stores the iteration counter when DFS visits node u for the 1st time 19 | // dfs_low[u] stores the lowest dfs_num reachable from the current DFS spanning subtree of node u 20 | // so dfs_num[u] == dfs_low[u] => u is a root of a SCC 21 | // then dfs_low[u] can only be made smaller if there is a back edge to form a cycle and v is currently visited 22 | // if we are at node u with node v as its neighbour and dfs_low[v] >= dfs_num[u], then u is an articulation point and edge u-v is a bridge 23 | 24 | int n, m, scc, dfsCounter; 25 | int dfs_num[MAX_N], dfs_low[MAX_N], visited[MAX_N]; 26 | stack st; 27 | vector adj[MAX_N], comp[MAX_N]; 28 | 29 | // Modified DFS 30 | void tarjan(int u) { 31 | dfs_low[u] = dfs_num[u] = dfsCounter++; 32 | visited[u] = 1; 33 | st.push(u); 34 | for (int v : adj[u]) { 35 | if (dfs_num[v] == -1) tarjan(v); 36 | if (visited[v]) dfs_low[u] = min(dfs_low[u], dfs_low[v]); 37 | } 38 | 39 | if (dfs_low[u] == dfs_num[u]) { 40 | scc++; 41 | while (st.size()) { 42 | int v = st.top(); st.pop(); 43 | visited[v] = 0; 44 | comp[scc].push_back(v); 45 | if (v == u) break; 46 | } 47 | } 48 | } 49 | 50 | void dfs(int u) { 51 | visited[u] = 1; 52 | for (int v : adj[u]) 53 | if (!visited[v]) 54 | dfs(v); 55 | } 56 | 57 | void solve() { 58 | cin >> n >> m; 59 | for (int i = 0; i < m; i++) { 60 | int u, v; cin >> u >> v; 61 | adj[u].push_back(v); 62 | } 63 | memset(dfs_low, -1, sizeof dfs_low); 64 | memset(dfs_num, -1, sizeof dfs_num); 65 | for (int i = 1; i <= n; i++) 66 | if (dfs_num[i] == -1) 67 | tarjan(i); 68 | 69 | if (scc == 1) cout << "YES\n"; 70 | else { 71 | cout << "NO\n"; 72 | memset(visited, 0, sizeof visited); 73 | dfs(comp[1][0]); 74 | if (!visited[comp[2][0]]) 75 | cout << comp[1][0] << " " << comp[2][0] << "\n"; 76 | else 77 | cout << comp[2][0] << " " << comp[1][0] << "\n"; 78 | } 79 | } 80 | 81 | int main() { 82 | ios_base::sync_with_stdio(0); 83 | cin.tie(0); cout.tie(0); 84 | // freopen("input.txt", "r", stdin); 85 | // freopen("output.txt", "w", stdout); 86 | 87 | int tc; tc = 1; 88 | for (int t = 1; t <= tc; t++) { 89 | // cout << "Case #" << t << ": "; 90 | solve(); 91 | } 92 | } -------------------------------------------------------------------------------- /Graphs/Topological Sort/README.md: -------------------------------------------------------------------------------- 1 | # Topological Ordering 2 | - Definition: the topological ordering of a **directed** graph is a linear ordering of its vertices such that for every directed edge u->v, **u comes before v** 3 | - There are 2 common ways to find the topoligical order: 4 | - The 1st way is to use the **reverse** of the traversal path of a DFS 5 | - The 2nd way is to greedily take all nodes with **in_deg == 0** and push them into the topological ordering, then decrease the in_deg of other nodes accordingly (implementation using a C++ STL queue) 6 | -------------------------------------------------------------------------------- /Graphs/Topological Sort/Topological Sort (DFS).cpp: -------------------------------------------------------------------------------- 1 | // Traversal path of a typical DFS is a reverse topological order 2 | // Problem link: https://cses.fi/problemset/task/1679 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, m, visited[MAX_N]; 17 | vector adj[MAX_N], topo; 18 | 19 | void dfs(int u) { 20 | visited[u] = 1; 21 | for (int v : adj[u]) { 22 | if (!visited[v]) dfs(v); 23 | else if (visited[v] == 1) { 24 | cout << "IMPOSSIBLE\n"; 25 | exit(0); 26 | } 27 | } 28 | visited[u] = 2; 29 | topo.push_back(u); 30 | } 31 | 32 | void solve() { 33 | cin >> n >> m; 34 | for (int i = 0; i < m; i++) { 35 | int u, v; cin >> u >> v; 36 | adj[u].push_back(v); 37 | } 38 | for (int i = 1; i <= n; i++) 39 | if (!visited[i]) 40 | dfs(i); 41 | reverse(topo.begin(), topo.end()); 42 | for (int x : topo) cout << x << " "; 43 | cout << "\n"; 44 | } 45 | 46 | int main() { 47 | ios_base::sync_with_stdio(0); 48 | cin.tie(0); cout.tie(0); 49 | // freopen("input.txt", "r", stdin); 50 | // freopen("output.txt", "w", stdout); 51 | 52 | int tc; tc = 1; 53 | for (int t = 1; t <= tc; t++) { 54 | // cout << "Case #" << t << ": "; 55 | solve(); 56 | } 57 | } -------------------------------------------------------------------------------- /Graphs/Topological Sort/Topological Sort (in_deg).cpp: -------------------------------------------------------------------------------- 1 | // Greedily take all nodes with in_deg == 0 and push them into the topological ordering, then decrease the in_deg of other nodes accordingly 2 | // Problem link: https://cses.fi/problemset/task/1679 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 1; 12 | const int MOD = 1e9 + 7; 13 | const int INF = 1e9; 14 | const ll LINF = 1e18; 15 | 16 | int n, m, visited[MAX_N], in_deg[MAX_N]; 17 | vector adj[MAX_N], topo; 18 | 19 | void build_topo() { 20 | for (int u = 1; u <= n; u++) 21 | for (int v : adj[u]) 22 | in_deg[v]++; 23 | queue q; 24 | for (int u = 1; u <= n; u++) 25 | if (in_deg[u] == 0) 26 | q.push(u); 27 | while (q.size()) { 28 | int u = q.front(); q.pop(); 29 | topo.push_back(u); 30 | for (int v : adj[u]) { 31 | in_deg[v]--; 32 | if (in_deg[v] == 0) q.push(v); 33 | } 34 | } 35 | // detect cycle 36 | for (int i = 1; i <= n; i++) { 37 | if (in_deg[i]) { 38 | cout << "IMPOSSIBLE\n"; 39 | exit(0); 40 | } 41 | } 42 | } 43 | 44 | void solve() { 45 | cin >> n >> m; 46 | for (int i = 0; i < m; i++) { 47 | int u, v; cin >> u >> v; 48 | adj[u].push_back(v); 49 | } 50 | build_topo(); 51 | for (int x : topo) cout << x << " "; 52 | cout << "\n"; 53 | } 54 | 55 | int main() { 56 | ios_base::sync_with_stdio(0); 57 | cin.tie(0); cout.tie(0); 58 | // freopen("input.txt", "r", stdin); 59 | // freopen("output.txt", "w", stdout); 60 | 61 | int tc; tc = 1; 62 | for (int t = 1; t <= tc; t++) { 63 | // cout << "Case #" << t << ": "; 64 | solve(); 65 | } 66 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Nguyen Cao Duy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Mathematics/Binomial Coefficients.cpp: -------------------------------------------------------------------------------- 1 | // Quick calculation of nCk 2 | // Time complexity: O(1) per query, O(n) precomputation 3 | // Precompute all the factorials and modular inverse to calculate nCk = n!/(k!(n-k)!) 4 | // Problem link: https://cses.fi/problemset/task/1079 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 5; 14 | const ll MOD = 1e9 + 7; 15 | const ll INF = 1e9; 16 | 17 | ll qexp(ll a, ll b, ll m) { 18 | ll res = 1; 19 | while (b) { 20 | if (b % 2) res = res * a % m; 21 | a = a * a % m; 22 | b /= 2; 23 | } 24 | return res; 25 | } 26 | 27 | vector fact, invf; 28 | 29 | void precompute(int n) { 30 | fact.assign(n + 1, 1); 31 | for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % MOD; 32 | invf.assign(n + 1, 1); 33 | invf[n] = qexp(fact[n], MOD - 2, MOD); 34 | for (int i = n - 1; i > 0; i--) invf[i] = invf[i + 1] * (i + 1) % MOD; 35 | } 36 | 37 | ll nCk(int n, int k) { 38 | if (k < 0 || k > n) return 0; 39 | return fact[n] * invf[k] % MOD * invf[n - k] % MOD; 40 | // return fact[n] * qexp(fact[k], MOD - 2, MOD) % MOD * qexp(fact[n - k], MOD - 2, MOD) % MOD; 41 | } 42 | 43 | // A trick to calculate large factorial without overflowing is to take log at every step when precompute and take exponential when calculating 44 | // Don't need invf[] now because it is the same as negative log of fact 45 | vector log_fact; 46 | void precompute_log(int n) { 47 | log_fact.assign(n + 1, 0.0); 48 | log_fact[0] = 0.0; 49 | for (int i = 1; i <= n; i++) log_fact[i] = log_fact[i - 1] + log(i); 50 | } 51 | 52 | ll log_nCk(int n, int k) { 53 | if (k < 0 || k > n) return 0; 54 | return exp(log_fact[n] - log_fact[n - k] - log_fact[k]); 55 | } 56 | 57 | void solve() { 58 | int n, k; cin >> n >> k; 59 | cout << nCk(n, k) << "\n"; 60 | } 61 | 62 | int main() { 63 | ios_base::sync_with_stdio(0); 64 | cin.tie(0); cout.tie(0); 65 | precompute(1e6); 66 | int tc = 1; 67 | cin >> tc; 68 | for (int t = 1; t <= tc; t++) { 69 | // cout << "Case #" << t << ": "; 70 | solve(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Mathematics/Fibonacci.cpp: -------------------------------------------------------------------------------- 1 | // Find the n-th Fibonacci number using matrix multiplication and binary exponentiation 2 | // This trick can also be used to optimised certain DP problems 3 | // Time complexity: O(2^3 * logn) 4 | // Problem link: https://cses.fi/problemset/task/1722 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 5; 14 | const ll MOD = 1e9 + 7; 15 | const ll INF = 1e9; 16 | 17 | template struct Modular { 18 | int v; explicit operator int() const { return v; } // explicit -> don't silently convert to int 19 | Modular() { v = 0; } 20 | Modular(ll _v) { v = int((-_MOD < _v && _v < _MOD) ? _v : _v % _MOD); if (v < 0) v += _MOD; } 21 | friend std::ostream& operator<<(std::ostream& out, const Modular& n) { return out << int(n); } 22 | friend std::istream& operator>>(std::istream& in, Modular& n) { ll v_; in >> v_; n = Modular(v_); return in; } 23 | 24 | friend bool operator==(const Modular& a, const Modular& b) { return a.v == b.v; } 25 | friend bool operator!=(const Modular& a, const Modular& b) { return a.v != b.v; } 26 | friend bool operator<(const Modular& a, const Modular& b) { return a.v < b.v; } 27 | 28 | Modular& operator+=(const Modular& m) { if ((v += m.v) >= _MOD) v -= _MOD; return *this; } 29 | Modular& operator-=(const Modular& m) { if ((v -= m.v) < 0) v += _MOD; return *this; } 30 | Modular& operator*=(const Modular& m) { v = int((ll)v*m.v%_MOD); return *this; } 31 | Modular& operator/=(const Modular& m) { return (*this) *= inv(m); } 32 | Modular operator-() const { return Modular(-v); } 33 | Modular& operator++() { return *this += 1; } 34 | Modular& operator--() { return *this -= 1; } 35 | friend Modular pow(Modular a, ll p) { 36 | Modular ans = 1; assert(p >= 0); 37 | for (; p; p /= 2, a *= a) if (p&1) ans *= a; 38 | return ans; 39 | } 40 | friend Modular inv(const Modular& a) { assert(a.v != 0); return pow(a,_MOD-2); } 41 | 42 | friend Modular operator+(Modular a, const Modular& b) { return a += b; } 43 | friend Modular operator-(Modular a, const Modular& b) { return a -= b; } 44 | friend Modular operator*(Modular a, const Modular& b) { return a *= b; } 45 | friend Modular operator/(Modular a, const Modular& b) { return a /= b; } 46 | friend Modular operator++(Modular& a, int) { Modular r = a; ++a; return r; }friend Modular operator--(Modular& a, int) { Modular r = a; --a; return r; } 47 | }; 48 | 49 | template struct matrix { 50 | vector> m; 51 | int r, c; 52 | matrix() : r(), c() {} 53 | matrix(int r, int c, T x) : r(r), c(c), m(r, vector(c, x)) {} 54 | matrix(int n) : matrix(n, n, 0) { // identity matrix 55 | for (int i = 0; i < n; i++) m[i][i] = 1; 56 | } 57 | matrix operator* (matrix b) { 58 | matrix a = *this; 59 | assert(a.c == b.r); 60 | matrix o(a.r, b.c, 0); 61 | for (int i = 0; i < a.r; i++) 62 | for (int j = 0; j < b.c; j++) 63 | for (int k = 0; k < a.c; k++) 64 | o.m[i][j] = o.m[i][j] + a.m[i][k] * b.m[k][j]; 65 | return o; 66 | } 67 | matrix operator^ (ll b) { 68 | matrix a = *this; 69 | assert(a.r == a.c); 70 | matrix o(a.r); 71 | while (b) { 72 | if (b % 2) o = o * a; 73 | a = a * a; 74 | b /= 2; 75 | } 76 | return o; 77 | } 78 | void print() { 79 | for (int i = 0; i < r; i++) { 80 | for (int j = 0; j < c; j++) cout << m[i][j] << " "; 81 | cout << "\n"; 82 | } 83 | } 84 | }; 85 | 86 | using mint = Modular; 87 | 88 | void solve() { 89 | ll n; cin >> n; 90 | matrix A(1, 2, 0); 91 | A.m[0][0] = 0; A.m[0][1] = 1; 92 | matrix B(2, 2, 0); 93 | B.m[0][0] = 0; B.m[0][1] = 1; 94 | B.m[1][0] = 1; B.m[1][1] = 1; 95 | A = A * (B ^ n); 96 | cout << A.m[0][0] << "\n"; 97 | } 98 | 99 | int main() { 100 | ios_base::sync_with_stdio(0); 101 | cin.tie(0); cout.tie(0); 102 | int tc = 1; 103 | // cin >> tc; 104 | for (int t = 1; t <= tc; t++) { 105 | // cout << "Case #" << t << ": "; 106 | solve(); 107 | } 108 | } -------------------------------------------------------------------------------- /Mathematics/GCD.cpp: -------------------------------------------------------------------------------- 1 | // Find the greatest common divisor (GCD) of two integers 2 | // Time complexity: O(log(min(a, b))) 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 5; 12 | const ll MOD = 1e9 + 7; 13 | const ll INF = 1e9; 14 | 15 | int gcd(int a, int b) { 16 | return b ? gcd(b, a % b) : a; 17 | } 18 | 19 | // extended version to find x, y such that ax + by = gcd(a, b) 20 | ll gcd(ll a, ll b, ll &x, ll &y) { 21 | if (b == 0) {x = 1, y = 0; return a;} 22 | ll x1, y1, d = gcd(b, a % b, x1, y1); 23 | x = y1; 24 | y = x1 - y1 * (a / b); 25 | return d; 26 | } 27 | 28 | // find a solution of a Linear Diophantine Equation 29 | bool lde(ll a, ll b, ll c, ll &x, ll &y) { 30 | ll d = gcd(abs(a), abs(b), x, y); 31 | if (c % d) return false; 32 | x *= c / d; 33 | y *= c / d; 34 | if (a < 0) x = -x; 35 | if (b < 0) y = -y; 36 | return true; 37 | } 38 | 39 | void shift(ll a, ll b, ll &x, ll &y, ll cnt) { 40 | x += cnt * b; 41 | y -= cnt * a; 42 | } 43 | 44 | ll inv_mod(ll a, ll m) { 45 | ll x, y; 46 | gcd(a, m, x, y); 47 | return (m + x % m) % m; 48 | } 49 | 50 | // solve ax = b (mod m) 51 | ll lce(ll a, ll b, ll m) { 52 | ll d = gcd(a, m); 53 | if (d != 1) { 54 | if (b % d) return -1; 55 | a /= d; b /= d; m /= d; 56 | } 57 | return b * inv_mod(a, m) % m; 58 | } 59 | 60 | void solve() { 61 | int a, b; cin >> a >> b; 62 | cout << gcd(a, b) << "\n"; 63 | 64 | // using C++ inbuilt function 65 | // cout << __gcd(a, b) << "\n"; 66 | } 67 | 68 | int main() { 69 | ios_base::sync_with_stdio(0); 70 | cin.tie(0); cout.tie(0); 71 | int tc = 1; 72 | // cin >> tc; 73 | for (int t = 1; t <= tc; t++) { 74 | // cout << "Case #" << t << ": "; 75 | solve(); 76 | } 77 | } -------------------------------------------------------------------------------- /Mathematics/Quick Exponention.cpp: -------------------------------------------------------------------------------- 1 | // Quick calculation of (a^b) mod m 2 | // Time complexity: O(logb) 3 | 4 | #include 5 | 6 | using namespace std; 7 | 8 | #define ar array 9 | #define ll long long 10 | 11 | const int MAX_N = 1e5 + 5; 12 | const ll MOD = 1e9 + 7; 13 | const ll INF = 1e9; 14 | 15 | // Recursive 16 | ll qexp(ll a, ll b, ll m) { 17 | if (b == 0) return 1; 18 | ll res = qexp(a, b / 2, m); 19 | res = res * res % m; 20 | if (b % 2) res = res * a % m; 21 | return res; 22 | } 23 | 24 | // Iterative (slightly faster) 25 | ll qexp(ll a, ll b, ll m) { 26 | ll res = 1; 27 | while (b) { 28 | if (b % 2) res = res * a % m; 29 | a = a * a % m; 30 | b /= 2; 31 | } 32 | return res; 33 | } 34 | 35 | void solve() { 36 | int a, b, m; cin >> a >> b >> m; 37 | cout << qexp(a, b, m) << "\n"; 38 | } 39 | 40 | int main() { 41 | ios_base::sync_with_stdio(0); 42 | cin.tie(0); cout.tie(0); 43 | int tc = 1; 44 | // cin >> tc; 45 | for (int t = 1; t <= tc; t++) { 46 | // cout << "Case #" << t << ": "; 47 | solve(); 48 | } 49 | } -------------------------------------------------------------------------------- /Mathematics/Sieve Of Eratosthenes.cpp: -------------------------------------------------------------------------------- 1 | // Generate the all primes <= n 2 | // Time complexity: O(nlog(logn)) for standard sieve, O(n) for linear sieve 3 | // Problem link: https://cses.fi/problemset/task/2417/ (using linear sieve to generate the mobius function) 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e6 + 5; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e9; 15 | 16 | // vector primes, is_prime, spf; 17 | 18 | // void sieve(int n) { 19 | // primes.clear(); 20 | // is_prime.assign(n + 1, 1); 21 | // spf.assign(n + 1, 0); 22 | // is_prime[0] = is_prime[1] = false; 23 | // for (ll i = 2; i <= n; i++) { 24 | // if (is_prime[i]) { 25 | // primes.push_back(i); 26 | // spf[i] = i; 27 | // for (ll j = i * i; j <= n; j += i) { 28 | // is_prime[j] = false; 29 | // spf[j] = i; 30 | // } 31 | // } 32 | // } 33 | // } 34 | 35 | // Linear sieve including calculating the smallest prime factor (spf), Mobius function, and Euler's totient function 36 | vector primes, is_prime, spf, mobius, phi; 37 | 38 | void sieve(int n) { 39 | primes.clear(); 40 | is_prime.assign(n + 1, 1); 41 | spf.assign(n + 1, 0); 42 | mobius.assign(n + 1, 0); 43 | phi.assign(n + 1, 0); 44 | is_prime[0] = is_prime[1] = 0; 45 | mobius[1] = phi[1] = 1; 46 | for (ll i = 2; i <= n; i++) { 47 | if (is_prime[i]) { 48 | primes.push_back(i); 49 | spf[i] = i; 50 | mobius[i] = -1; 51 | phi[i] = i - 1; 52 | } 53 | for (auto p : primes) { 54 | if (i * p > n || p > spf[i]) break; 55 | is_prime[i * p] = 0; 56 | spf[i * p] = p; 57 | mobius[i * p] = (spf[i] == p) ? 0 : -mobius[i]; 58 | phi[i * p] = (spf[i] == p) ? phi[i] * p : phi[i] * phi[p]; 59 | } 60 | } 61 | } 62 | 63 | void solve() { 64 | int n; cin >> n; 65 | vector cnt(MAX_N); 66 | while (n--) { 67 | int x; cin >> x; 68 | cnt[x]++; 69 | } 70 | ll ans = 0; 71 | for (int i = 1; i < MAX_N; i++) { 72 | if (!mobius[i]) continue; 73 | ll tmp = 0; 74 | for (int j = i; j < MAX_N; j += i) tmp += cnt[j]; 75 | ans += tmp * (tmp - 1) / 2 * mobius[i]; 76 | } 77 | cout << ans << "\n"; 78 | } 79 | 80 | int main() { 81 | ios_base::sync_with_stdio(0); 82 | cin.tie(0); cout.tie(0); 83 | sieve(MAX_N); 84 | int tc = 1; 85 | // cin >> tc; 86 | for (int t = 1; t <= tc; t++) { 87 | // cout << "Case #" << t << ": "; 88 | solve(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Others/2SAT.cpp: -------------------------------------------------------------------------------- 1 | // 2-SAT Problem 2 | // Time complexity: O(n + m), using Kosaraju to find SCCs 3 | // Problem link: https://cses.fi/problemset/task/1684/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | int n, m, scc, visited[2 * MAX_N], comp[2 * MAX_N]; 18 | char ans[MAX_N]; 19 | vector adj[2][2 * MAX_N], dfn; 20 | // adj[0] is the original graph, adj[1] is the transposed graph 21 | 22 | // t = 0 means 1st pass, t = 1 means 2nd pass 23 | void dfs(int u, int t) { 24 | visited[u] = 1; 25 | if (t == 1) comp[u] = scc; 26 | for (int v : adj[t][u]) { 27 | if (!visited[v]) { 28 | dfs(v, t); 29 | } 30 | } 31 | if (t == 0) dfn.push_back(u); 32 | } 33 | 34 | void kosaraju() { 35 | for (int i = 1; i <= 2 * n; i++) { 36 | if (!visited[i]) { 37 | dfs(i, 0); 38 | } 39 | } 40 | memset(visited, 0, sizeof visited); 41 | for (int i = 2 * n; i > 0; i--) { 42 | if (!visited[dfn[i]]) { 43 | scc++; 44 | dfs(dfn[i], 1); 45 | } 46 | } 47 | } 48 | 49 | void solve() { 50 | cin >> m >> n; 51 | for (int i = 0; i < m; i++) { 52 | int u1, u2; char c1, c2; cin >> c1 >> u1 >> c2 >> u2; 53 | u1 *= 2; u2 *= 2; 54 | if (c1 == '-') u1 ^= 1; 55 | if (c2 == '-') u2 ^= 1; 56 | adj[0][u1 ^ 1].push_back(u2); 57 | adj[0][u2 ^ 1].push_back(u1); 58 | } 59 | for (int i = 1; i <= 2 * n; i++) { 60 | for (int j : adj[0][i]) { 61 | adj[1][j].push_back(i); 62 | } 63 | } 64 | kosaraju(); 65 | for (int i = 1; i <= n; i++) { 66 | if (comp[2 * i] == comp[2 * i + 1]) { 67 | cout << "IMPOSSIBLE\n"; 68 | return; 69 | } 70 | ans[i] = (comp[2 * i] > comp[2 * i + 1]) ? '+' : '-'; 71 | } 72 | for (int i = 1; i <= n; i++) cout << ans[i] << " "; 73 | cout << "\n"; 74 | } 75 | 76 | int main() { 77 | ios_base::sync_with_stdio(0); 78 | cin.tie(0); cout.tie(0); 79 | //freopen("input.txt", "r", stdin); 80 | //freopen("output.txt", "w", stdout); 81 | 82 | int tc; tc = 1; 83 | for (int t = 1; t <= tc; t++) { 84 | //cout << "Case #" << t << ": "; 85 | solve(); 86 | } 87 | } -------------------------------------------------------------------------------- /Others/Closest_3_Points(Divide&Conquer).cpp: -------------------------------------------------------------------------------- 1 | // Problem link: https://www.codechef.com/LRNDSA04/problems/ACM14KP1 2 | 3 | #include 4 | 5 | using namespace std; 6 | 7 | #define ar array 8 | #define ll long long 9 | 10 | const int MAX_N = 1e5 + 1; 11 | const int MOD = 1e9 + 7; 12 | const int INF = 1e9; 13 | const ll LINF = 1e18; 14 | 15 | struct pt { 16 | double x, y; 17 | }; 18 | 19 | pt pts[MAX_N]; 20 | 21 | bool cmp_x(pt a, pt b) {return a.x < b.x;} 22 | bool cmp_y(pt a, pt b) {return a.y < b.y;} 23 | double dist(pt a, pt b) {return hypot(abs(a.x - b.x), abs(a.y - b.y));} 24 | double perimeter(pt a, pt b, pt c) {return dist(a, b) + dist(b, c) + dist(c, a);} 25 | 26 | double dac(int l, int r) { 27 | if (r - l <= 1) return INF; 28 | if (r - l == 2) return perimeter(pts[l], pts[l + 1], pts[l + 2]); 29 | 30 | int mid = (l + r) / 2; 31 | double d1 = dac(l, mid), d2 = dac(mid + 1, r); 32 | double ans = min(d1, d2); 33 | vector strip; 34 | for (int i = l; i <= r; i++) { 35 | if (abs(pts[i].x - pts[mid].x) < ans) strip.push_back(pts[i]); 36 | } 37 | sort(strip.begin(), strip.end(), cmp_y); 38 | for (int i = 0; i < strip.size(); i++) { 39 | for (int j = i + 1; j < strip.size() && (strip[j].y - strip[i].y) < ans; j++) { 40 | for (int k = j + 1; k < strip.size() && (strip[k].y - strip[j].y) < ans; k++) { 41 | ans = min(ans, perimeter(strip[i], strip[j], strip[k])); 42 | } 43 | } 44 | } 45 | return ans; 46 | } 47 | 48 | void solve() { 49 | int n; cin >> n; 50 | for (int i = 0; i < n; i++) cin >> pts[i].x >> pts[i].y; 51 | sort(pts, pts + n, cmp_x); 52 | cout << fixed << setprecision(10) << dac(0, n - 1) << "\n"; 53 | } 54 | 55 | int main() { 56 | ios_base::sync_with_stdio(0); 57 | cin.tie(0); cout.tie(0); 58 | // freopen("input.txt", "r", stdin); 59 | // freopen("output.txt", "w", stdout); 60 | 61 | int tc; cin >> tc; 62 | for (int t = 1; t <= tc; t++) { 63 | cout << "Case " << t << ": "; 64 | solve(); 65 | } 66 | } -------------------------------------------------------------------------------- /Others/Maximum Histogram Area (Monotonic Stack).cpp: -------------------------------------------------------------------------------- 1 | // Find the largest rectangular area in a histogram 2 | // Use a monotonic stack {val, pos} to find the left border and right border at each position 3 | // Time complexity: O(n) 4 | // Problem link: https://www.spoj.com/problems/HISTOGRA/ 5 | 6 | #include 7 | 8 | using namespace std; 9 | 10 | #define ar array 11 | #define ll long long 12 | 13 | const int MAX_N = 1e5 + 1; 14 | const int MOD = 1e9 + 7; 15 | const int INF = 1e9; 16 | const ll LINF = 1e18; 17 | 18 | 19 | 20 | void solve() { 21 | while (true) { 22 | int n; cin >> n; 23 | if (!n) return; 24 | 25 | int arr[n], l[n], r[n]; 26 | for (int i = 0; i < n; i++) cin >> arr[i]; 27 | 28 | stack st; 29 | // find left borders 30 | for (int i = 0; i < n; i++) { 31 | while (st.size() && arr[st.top()] >= arr[i]) st.pop(); 32 | l[i] = st.size() ? st.top() + 1 : 0; 33 | st.push(i); 34 | } 35 | // clear stack 36 | while (st.size()) st.pop(); 37 | // find right borders 38 | for (int i = n - 1; i >= 0; i--) { 39 | while (st.size() && arr[st.top()] >= arr[i]) st.pop(); 40 | r[i] = st.size() ? st.top() - 1 : n - 1; 41 | st.push(i); 42 | } 43 | 44 | ll mx = 0; 45 | for (int i = 0; i < n; i++) { 46 | ll cur = (ll) arr[i] * (r[i] - l[i] + 1); 47 | mx = max(mx, cur); 48 | } 49 | cout << mx << "\n"; 50 | } 51 | } 52 | 53 | int main() { 54 | ios_base::sync_with_stdio(0); 55 | cin.tie(0); cout.tie(0); 56 | // freopen("input.txt", "r", stdin); 57 | // freopen("output.txt", "w", stdout); 58 | 59 | int tc; tc = 1; 60 | for (int t = 1; t <= tc; t++) { 61 | // cout << "Case #" << t << ": "; 62 | solve(); 63 | } 64 | } -------------------------------------------------------------------------------- /Others/Median Heap.cpp: -------------------------------------------------------------------------------- 1 | // Given a stream of n input integers, maintain the median of the current array 2 | // Use a max heap to store the first half (<= median) 3 | // Use a min heap to store the second half (> median) 4 | // When a new number is inserted, compare it with the top of each heap and insert accordingly 5 | // Time complexity: O(nlogn) 6 | // Problem link: https://dunjudge.me/analysis/problems/338/ 7 | 8 | #include 9 | 10 | using namespace std; 11 | 12 | #define ar array 13 | #define ll long long 14 | 15 | const int MAX_N = 1e5 + 1; 16 | const int MOD = 1e9 + 7; 17 | const int INF = 1e9; 18 | const ll LINF = 1e18; 19 | 20 | // The current median is stored as lo.top() 21 | 22 | void solve() { 23 | int n; cin >> n; 24 | priority_queue lo; 25 | priority_queue, greater> hi; 26 | vector ans; 27 | while (n--) { 28 | string s; cin >> s; 29 | if (s == "PUSH") { 30 | int x; cin >> x; 31 | if (hi.empty() || x <= hi.top()) // insert x to the lo heap if possible 32 | lo.push(x); 33 | else 34 | hi.push(x); 35 | 36 | // the 2 heaps can become imbalanced, so need to fix it 37 | if (lo.size() > hi.size() + 1) { 38 | hi.push(lo.top()); 39 | lo.pop(); 40 | } 41 | if (lo.size() < hi.size()) { 42 | lo.push(hi.top()); 43 | hi.pop(); 44 | } 45 | } 46 | else { 47 | // remove the current median 48 | lo.pop(); 49 | // the 2 heaps can become imbalanced, so need to fix it 50 | if (lo.size() != hi.size()) { 51 | lo.push(hi.top()); 52 | hi.pop(); 53 | } 54 | } 55 | } 56 | 57 | // printing the final array in increasing order 58 | while (!lo.empty()) { 59 | ans.push_back(lo.top()); 60 | lo.pop(); 61 | } 62 | // need to reverse as we are popping from a max heap 63 | reverse(ans.begin(), ans.end()); 64 | while (!hi.empty()) { 65 | ans.push_back(hi.top()); 66 | hi.pop(); 67 | } 68 | for (int x : ans) 69 | cout << x << " "; 70 | } 71 | 72 | int main() { 73 | ios_base::sync_with_stdio(0); 74 | cin.tie(0); cout.tie(0); 75 | // freopen("input.txt", "r", stdin); 76 | // freopen("output.txt", "w", stdout); 77 | 78 | int tc; tc = 1; 79 | for (int t = 1; t <= tc; t++) { 80 | // cout << "Case #" << t << ": "; 81 | solve(); 82 | } 83 | } -------------------------------------------------------------------------------- /Others/Meet In The Middle.cpp: -------------------------------------------------------------------------------- 1 | // Given an array of n numbers (n <= 40), count the number of subsets with sum x (x <= 10^9) 2 | // Problem link: https://cses.fi/problemset/task/1628/ 3 | 4 | /* 5 | As x <= 10^9, DP is not possible 6 | 7 | As n <= 40, some brute force is possible 8 | However, generating all subsets results in O(2^n) time complexity => TLE 9 | 10 | "Meet in the middle" technique can speed up from O(2^n) to O(2^(n/2)) => AC 11 | 12 | Divide the array into 2 sets, generate all possible subsets in each set 13 | Iterating through all values in one set and use binary search on the other set to find the complement to get a total sum of x 14 | Time complexity: 2 * O(2^(n/2)) 15 | */ 16 | 17 | #include 18 | 19 | using namespace std; 20 | 21 | #define ar array 22 | #define ll long long 23 | 24 | const int MAX_N = 1e5 + 1; 25 | const int MOD = 1e9 + 7; 26 | const int INF = 1e9; 27 | const ll LINF = 1e18; 28 | 29 | 30 | 31 | void solve() { 32 | int n, x; cin >> n >> x; 33 | int m1 = n / 2, m2 = n - m1; 34 | int arr1[m1], arr2[m2]; 35 | for (int i = 0; i < m1; i++) cin >> arr1[i]; 36 | for (int i = 0; i < m2; i++) cin >> arr2[i]; 37 | 38 | vector sum1, sum2; 39 | for (int i = 0; i < (1 << m1); i++) { 40 | ll cur = 0; 41 | for (int j = 0; j < m1; j++) 42 | if (i & (1 << j)) 43 | cur += arr1[j]; 44 | sum1.push_back(cur); 45 | } 46 | for (int i = 0; i < (1 << m2); i++) { 47 | ll cur = 0; 48 | for (int j = 0; j < m2; j++) 49 | if (i & (1 << j)) 50 | cur += arr2[j]; 51 | sum2.push_back(cur); 52 | } 53 | sort(sum1.begin(), sum1.end()); 54 | sort(sum2.begin(), sum2.end()); 55 | 56 | ll ans = 0; 57 | for (ll s1 : sum1) 58 | ans += upper_bound(sum2.begin(), sum2.end(), x - s1) - lower_bound(sum2.begin(), sum2.end(), x - s1); 59 | cout << ans; 60 | } 61 | 62 | int main() { 63 | ios_base::sync_with_stdio(0); 64 | cin.tie(0); cout.tie(0); 65 | // freopen("input.txt", "r", stdin); 66 | // freopen("output.txt", "w", stdout); 67 | 68 | int tc; tc = 1; 69 | for (int t = 1; t <= tc; t++) { 70 | // cout << "Case #" << t << ": "; 71 | solve(); 72 | } 73 | } -------------------------------------------------------------------------------- /Others/N Queens.cpp: -------------------------------------------------------------------------------- 1 | // Count the number of ways to place the queens so that no two queens are attacking each other 2 | // Use backtracking 3 | // Problem link: https://cses.fi/problemset/task/1624/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | const int n = 8; 18 | 19 | int r[n], c[n], d1[2 * n], d2[2 * n], blocked[n][n], ans; 20 | 21 | void place(int j) { 22 | if (j == n) { 23 | ans++; 24 | return; 25 | } 26 | if (c[j]) place(j + 1); 27 | else { 28 | for (int i = 0; i < n; i++) { 29 | if (!blocked[i][j] && !r[i] && !d1[i + j] && !d2[i - j + n]) { 30 | blocked[i][j] = r[i] = d1[i + j] = d2[i - j + n] = 1; 31 | place(j + 1); 32 | blocked[i][j] = r[i] = d1[i + j] = d2[i - j + n] = 0; 33 | } 34 | } 35 | } 36 | } 37 | 38 | void solve() { 39 | for (int i = 0; i < n; i++) { 40 | for (int j = 0; j < n; j++) { 41 | char x; cin >> x; 42 | if (x == '*') blocked[i][j] = 1; 43 | } 44 | } 45 | place(0); 46 | cout << ans; 47 | } 48 | int main() { 49 | ios_base::sync_with_stdio(0); 50 | cin.tie(0); cout.tie(0); 51 | // freopen("input.txt", "i", stdin); 52 | // freopen("output.txt", "w", stdout); 53 | 54 | int tc; tc = 1; 55 | for (int t = 1; t <= tc; t++) { 56 | // cout << "Case #" << t << ": "; 57 | solve(); 58 | } 59 | } -------------------------------------------------------------------------------- /Others/Offline Dynamic Connectivity.cpp: -------------------------------------------------------------------------------- 1 | // Use DSU (with rollback) to solve offline dynamic connectivity problems 2 | // Time complexity: O(qlogqlogn) 3 | // Problem link: https://dunjudge.me/analysis/problems/422/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 3e5 + 1; 13 | const int MOD = 1e9 + 7; 14 | const int INF = 1e9; 15 | const ll LINF = 1e18; 16 | 17 | struct DSU { 18 | int num; 19 | vector p, sz; 20 | stack st; 21 | void init(int n) { 22 | num = n; 23 | p.resize(n); for (int i = 0; i < n; i++) p[i] = i; 24 | sz.assign(n, 1); 25 | } 26 | int find(int u) {return u == p[u] ? u : find(p[u]);} 27 | bool same(int u, int v) {return find(u) == find(v);} 28 | void merge(int u, int v) { 29 | if (same(u, v)) return; 30 | u = find(u), v = find(v); 31 | if (sz[u] > sz[v]) swap(u, v); 32 | num--; 33 | sz[v] += sz[u]; 34 | p[u] = v; 35 | st.push(u); 36 | } 37 | void rollback(int t) { 38 | while (st.size() > t) { 39 | int u = st.top(); st.pop(); 40 | num++; 41 | sz[p[u]] -= sz[u]; 42 | p[u] = u; 43 | } 44 | } 45 | }; 46 | 47 | int n, m, q, us[MAX_N], vs[MAX_N], other[MAX_N], ans[MAX_N]; 48 | vector> qs; // {time, type, id, u, v} 49 | map,int> mp; 50 | DSU uf; 51 | 52 | void dco(int l, int r) { 53 | if (l > r) return; 54 | if (l == r) { 55 | auto [t, c, id, u, v] = qs[l]; 56 | if (c == 2) ans[id] = uf.same(u, v); 57 | return; 58 | } 59 | int mid = (l + r) / 2; 60 | int save = uf.st.size(); 61 | for (int i = mid + 1; i <= r; i++) { 62 | auto [t, c, id, u, v] = qs[i]; 63 | if (c == 1 && other[i] < l) { // query covers [l, mid] 64 | uf.merge(u, v); 65 | } 66 | } 67 | dco(l, mid); 68 | uf.rollback(save); 69 | for (int i = l; i <= mid; i++) { 70 | auto [t, c, id, u, v] = qs[i]; 71 | if (c == 0 && other[i] > r) { // query covers [mid + 1, r] 72 | uf.merge(u, v); 73 | } 74 | } 75 | dco(mid + 1, r); 76 | uf.rollback(save); 77 | } 78 | 79 | void solve() { 80 | cin >> n >> m; uf.init(n); 81 | for (int i = 0; i < m; i++) { 82 | int u, v, s, e; cin >> u >> v >> s >> e; 83 | qs.push_back({s, 0, -1, u, v}); 84 | qs.push_back({e + 1, 1, -1, u, v}); 85 | } 86 | cin >> q; 87 | for (int i = 0; i < q; i++) { 88 | int u, v, t; cin >> u >> v >> t; 89 | qs.push_back({t, 2, i, u, v}); 90 | } 91 | sort(qs.begin(), qs.end()); 92 | for (int i = 0; i < qs.size(); i++) { 93 | auto [t, c, id, u, v] = qs[i]; 94 | if (c == 0) { 95 | mp[{u, v}] = i; 96 | other[i] = qs.size(); 97 | } 98 | if (c == 1) { 99 | other[mp[{u, v}]] = i; 100 | other[i] = mp[{u, v}]; 101 | } 102 | } 103 | dco(0, qs.size() - 1); 104 | for (int i = 0; i < q; i++) { 105 | cout << (ans[i] ? "Y" : "N") << "\n"; 106 | } 107 | } 108 | 109 | int main() { 110 | ios_base::sync_with_stdio(0); 111 | cin.tie(0); cout.tie(0); 112 | // freopen("input.txt", "r", stdin); 113 | // freopen("output.txt", "w", stdout); 114 | 115 | int tc; tc = 1; 116 | for (int t = 1; t <= tc; t++) { 117 | // cout << "Case #" << t << ": "; 118 | solve(); 119 | } 120 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Competitive Programming 2 | My own templates and implementation of important algorithms and data structures for competitive programming 3 | 4 | 5 | My profile: [Codeforces](https://codeforces.com/profile/ncduy0303), [AtCoder](https://atcoder.jp/users/ncduy0303), [LeetCode](https://leetcode.com/u/caoduy73) 6 | 7 | ## Star History 8 | 9 | [![Star History Chart](https://api.star-history.com/svg?repos=ncduy0303/Competitive-Programming&type=Date)](https://star-history.com/#ncduy0303/Competitive-Programming&Date) 10 | 11 | ## Contest templates 12 | - [My template C++](Contest%20Template/main.cpp) 13 | 14 | ## Graph 15 | - Graph Traversing ([DFS](Graphs/Graph%20Traversal/DFS.cpp), [BFS](Graphs/Graph%20Traversal/BFS.cpp)) 16 | - [Flood Fill](Graphs/Graph%20Traversal/Flood%20Fill.cpp) 17 | - Minimum Spanning Tree ([Kruskal](Graphs/Minimum%20Spanning%20Tree/Kruskal.cpp), [Prim](Graphs/Minimum%20Spanning%20Tree/Prim.cpp)) 18 | - Shortest Paths ([Dijkstra](Graphs/Shortest%20Paths/Dijkstra.cpp), [Bellman-Ford](Graphs/Shortest%20Paths/Bellman_Ford.cpp), [0-1 BFS](Graphs/Shortest%20Paths/0-1%20BFS.cpp), [Floyd Warshall](Graphs/Shortest%20Paths/Floyd_Warshall.cpp)) 19 | - [Bridges and Articulation Points](Graphs/Strongly%20Connected%20Components%20(SSCs)/Bridges&ArticulationPoints.cpp) 20 | - Strongly Connected Components ([Tarjan](Graphs/Strongly%20Connected%20Components%20(SSCs)/Tarjan.cpp), [Kosaraju](Graphs/Strongly%20Connected%20Components%20(SSCs)/Kosaraju.cpp)) 21 | - [Bipartite Matching](Graphs/Graph%20Traversal/Bipartite.cpp) 22 | - Topological Sort ([DFS](Graphs/Topological%20Sort/Topological%20Sort%20(DFS).cpp), [in_deg](Graphs/Topological%20Sort/Topological%20Sort%20(in_deg).cpp)) 23 | - Maximum FLow ([Edmonds-Karp](Graphs/Max%20Flow/Edmonds_Karp.cpp), [Dinic](Graphs/Max%20Flow/Dinic.cpp)) 24 | - Lowest Common Ancestor ([Binary Lifting](Graphs/Lowest%20Common%20Ancestor/LCA%20(Binary%20Lifting).cpp), [RMQ](Graphs/Lowest%20Common%20Ancestor/LCA%20(RMQ).cpp)) 25 | 26 | ## Dynamic Programming 27 | - [0-1 Knapsack](Dynamic%20Programming/(0-1)%20Knapsack.cpp) 28 | - [Coin Change](Dynamic%20Programming/Coin%20Change.cpp) 29 | - Max Sum Subarray: [1D](Dynamic%20Programming/1D%20Max%20Sum%20(Kanade).cpp), [2D](Dynamic%20Programming/2D%20Max%20Sum.cpp) 30 | - [Longest Common Subsequence](Dynamic%20Programming/Longest%20Common%20Subsequence%20(LCS).cpp) 31 | - [Longest Increasing Subsequence](Dynamic%20Programming/Longest%20Increasing%20Subsequence%20(LIS).cpp) 32 | - [Digit DP](Dynamic%20Programming/Digit%20DP.cpp) 33 | - [SOS DP](Dynamic%20Programming/SOS%20DP.cpp) 34 | - [Weighted Job Scheduling](Dynamic%20Programming/Weighted%20Job%20Scheduling.cpp) 35 | - [Cutting Sticks](Dynamic%20Programming/Cutting%20Sticks.cpp) 36 | - [Matrix Chain](Dynamic%20Programming/Matrix%20Chain.cpp) 37 | - [Elevator Rides](Dynamic%20Programming/Elevator%20Rides.cpp) 38 | - [Travelling Salesman Problem](Dynamic%20Programming/Traveling%20Salesman%20Problem%20(TSP).cpp) 39 | - [Deque Trick](Dynamic%20Programming/Deque%20Trick.cpp) 40 | - [Divide & Conquer Trick](Dynamic%20Programming/D&C%20Trick.cpp) 41 | - [Convex Hull Trick](Dynamic%20Programming/Convex%20Hull%20Trick%20&%20Li-Chao%20Segment%20Tree.cpp) 42 | 43 | ## Data Structure 44 | - [Sparse Table](Data%20Structures/Sparse%20Table.cpp) 45 | - [Fenwick Tree](Data%20Structures/Fenwick%20Tree/Fenwick%20Tree%20(point%20update,%20range%20query).cpp) 46 | - [Segment Tree](Data%20Structures/Segment%20Tree/Segment%20Tree%20(Recursive).cpp) 47 | - [Treap](Data%20Structures/Treap.cpp) 48 | - [SQRT Decomposition + Mo's Algorithm](Data%20Structures/SQRT.cpp) 49 | - [Disjoint Set Union](Data%20Structures/DSU.cpp) 50 | - [Trie](Data%20Structures/Trie.cpp) 51 | - [Suffix Array](Data%20Structures/Suffix%20Array.cpp) 52 | - [Policy-based data structures C++ STL](Data%20Structures/PBDS.cpp) 53 | - [Heavy Light Decomposition](Data%20Structures/HLD.cpp) 54 | 55 | ## String Algorithm 56 | - Pattern Searching ([KMP](String%20Processing/KMP%20(Prefix%20function).cpp), [Z-Algorithm](String%20Processing/Z-algo%20(Z%20function).cpp), [Rabin-Karp](String%20Processing/String%20Hashing%20(Rabin-Karp).cpp)) 57 | 58 | ## Number Theory 59 | - [Sieve of Eratosthenes](Mathematics/Sieve%20Of%20Eratosthenes.cpp) 60 | - [Greatest Common Divisor (Euclidean Algorithm)](Mathematics/GCD.cpp) 61 | - [Quick Exponentiation](Mathematics/Quick%20Exponention.cpp) 62 | - [Fibonacci](Mathematics/Fibonacci.cpp) 63 | - [Binomial Coefficients](Mathematics/Binomial%20Coefficients.cpp) 64 | 65 | ## Computational Geometry 66 | - Sweep Line: [Closet Pairs](Geometry/Sweep%20Line/Closest%20Pairs.cpp), [Rectangle Union](Geometry/Sweep%20Line/Rectangle%20Union.cpp) 67 | 68 | ## Other Classic Problems 69 | - [N-queen](Others/N%20Queens.cpp) 70 | - [Median Heap](Others/Median%20Heap.cpp) 71 | - [Maximum Histogram Area](Others/Maximum%20Histogram%20Area%20(Monotonic%20Stack).cpp) 72 | - [Meet In The Middle](Others/Meet%20In%20The%20Middle.cpp) 73 | - [2-SAT](Others/2SAT.cpp) 74 | - [Offline Dynamic Connectivity](Others/Offline%20Dynamic%20Connectivity.cpp) 75 | - [Closest Points (Divide & Conquer)](/Others/Closest_3_Points(Divide&Conquer).cpp) 76 | -------------------------------------------------------------------------------- /String Processing/KMP (Prefix function).cpp: -------------------------------------------------------------------------------- 1 | // Given a string s (with length n) and a pattern p (with length m), find all occurrence of p in s 2 | // Time complexity: O(n + m) 3 | // Problem link: https://cses.fi/problemset/task/1753/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 5; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e9; 15 | 16 | // f[i] = length of the longest proper prefix of the substring s[0...i] which is also a suffix of this substring 17 | vector prefix_func(string s) { 18 | int n = s.size(); 19 | vector f(n); 20 | for (int i = 1; i < n; i++) { 21 | int j = f[i - 1]; 22 | while (j && s[i] != s[j]) j = f[j - 1]; 23 | f[i] = j + (s[i] == s[j]); 24 | } 25 | return f; 26 | } 27 | 28 | int cnt_occ(string s, string t) { 29 | string ts = t + "#" + s; 30 | int n = t.size(), m = s.size(), nm = ts.size(); 31 | auto f = prefix_func(ts); 32 | int res = 0; 33 | for (int i = n + 1; i < nm; i++) res += (f[i] == n); 34 | return res; 35 | } 36 | 37 | void solve() { 38 | string s, t; cin >> s >> t; 39 | cout << cnt_occ(s, t) << "\n"; 40 | } 41 | 42 | int main() { 43 | ios_base::sync_with_stdio(0); 44 | cin.tie(0); cout.tie(0); 45 | int tc = 1; 46 | // cin >> tc; 47 | for (int t = 1; t <= tc; t++) { 48 | // cout << "Case #" << t << ": "; 49 | solve(); 50 | } 51 | } -------------------------------------------------------------------------------- /String Processing/String Hashing (Rabin-Karp).cpp: -------------------------------------------------------------------------------- 1 | // String Hashing 2 | // Consider carefully the choice of 'base' and 'mod' 3 | // 'base' should be greater than the number of characters in the input alphabet 4 | // 'mod' should be a large prime like 1e9 + 7 5 | 6 | // should always convert 'a' into 1 instead 0 7 | // should randomise the value of 'base' to avoid hacking 8 | // should use > 1 'base' to reduce collision rate 9 | 10 | // Example of using Hashing for String Matching (Rabin-Karp) 11 | // Problem link: https://cses.fi/problemset/task/1753 12 | 13 | #include 14 | 15 | using namespace std; 16 | 17 | #define ar array 18 | #define ll long long 19 | 20 | const int MAX_N = 1e5 + 5; 21 | const ll MOD = 1e9 + 7; 22 | const ll INF = 1e9; 23 | 24 | mt19937 rng(chrono::steady_clock::now().time_since_epoch().count()); 25 | ll rand(ll l, ll r) {return uniform_int_distribution(l, r)(rng);} 26 | const int BASE = rand(300, 1e9); 27 | const int NUM_MOD = 2; 28 | const ll MODS[] = {(int)1e9 + 2277, (int)1e9 + 5277}; 29 | struct Hash { 30 | vector H[NUM_MOD], P[NUM_MOD]; 31 | Hash(string s) { 32 | for (int i = 0; i < NUM_MOD; i++) { 33 | P[i].push_back(1); 34 | H[i].push_back(0); 35 | } 36 | for (char c : s) { 37 | for (int i = 0; i < NUM_MOD; i++) { 38 | P[i].push_back(P[i].back() * BASE % MODS[i]); 39 | H[i].push_back((H[i].back() * BASE + c) % MODS[i]); 40 | } 41 | } 42 | } 43 | ar operator()(int l, int r) { 44 | ar res; 45 | for (int i = 0; i < NUM_MOD; i++) { 46 | res[i] = (H[i][r + 1] - H[i][l] * P[i][r + 1 - l]) % MODS[i]; 47 | if (res[i] < 0) res[i] += MODS[i]; 48 | } 49 | return res; 50 | } 51 | }; 52 | 53 | int cnt_occ(string s, string t) { 54 | int n = s.size(), m = t.size(); 55 | Hash hs(s), ht(t); 56 | int res = 0; 57 | for (int i = 0, j = m - 1; j < n; i++, j++) { 58 | res += (hs(i, j) == ht(0, m - 1)); 59 | } 60 | return res; 61 | } 62 | 63 | void solve() { 64 | string s, t; cin >> s >> t; 65 | cout << cnt_occ(s, t) << "\n"; 66 | } 67 | 68 | int main() { 69 | ios_base::sync_with_stdio(0); 70 | cin.tie(0); cout.tie(0); 71 | int tc = 1; 72 | // cin >> tc; 73 | for (int t = 1; t <= tc; t++) { 74 | // cout << "Case #" << t << ": "; 75 | solve(); 76 | } 77 | } -------------------------------------------------------------------------------- /String Processing/Z-algo (Z function).cpp: -------------------------------------------------------------------------------- 1 | // Given a string s (with length n) and a pattern p (with length m), find all the occurrence of p in s 2 | // Time complexity: O(n + m) 3 | // Problem link: https://cses.fi/problemset/task/1753/ 4 | 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define ar array 10 | #define ll long long 11 | 12 | const int MAX_N = 1e5 + 5; 13 | const ll MOD = 1e9 + 7; 14 | const ll INF = 1e9; 15 | 16 | // f[i] = length of the longest common prefix between s and the substring s[i...n-1] 17 | vector z_func(string s) { 18 | int n = s.size(); 19 | vector f(n); // f[0] = 0 by default 20 | for (int i = 1, l = 0, r = 0; i < n; i++) { 21 | if (i <= r) f[i] = min(r - i + 1, f[i - l]); 22 | while (i + f[i] < n && s[f[i]] == s[i + f[i]]) f[i]++; 23 | if (i + f[i] - 1 > r) l = i, r = i + f[i] - 1; 24 | } 25 | return f; 26 | } 27 | 28 | int cnt_occ(string s, string t) { 29 | string ts = t + "#" + s; 30 | int n = t.size(), m = s.size(), nm = ts.size(); 31 | auto f = z_func(ts); 32 | int res = 0; 33 | for (int i = n + 1; i < nm; i++) res += (f[i] == n); 34 | return res; 35 | } 36 | 37 | void solve() { 38 | string s, t; cin >> s >> t; 39 | cout << cnt_occ(s, t) << "\n"; 40 | } 41 | 42 | int main() { 43 | ios_base::sync_with_stdio(0); 44 | cin.tie(0); cout.tie(0); 45 | int tc = 1; 46 | // cin >> tc; 47 | for (int t = 1; t <= tc; t++) { 48 | // cout << "Case #" << t << ": "; 49 | solve(); 50 | } 51 | } -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman --------------------------------------------------------------------------------