Repository: radoslav11/Coding-Library Branch: master Commit: 669270c03e85 Files: 132 Total size: 324.3 KB Directory structure: gitextract_ns7a50wl/ ├── README.md ├── data_structures/ │ ├── clever_adding_intervals_set.hpp │ ├── compressed_fenwick.hpp │ ├── decremental_constant_set.hpp │ ├── fenwick.hpp │ ├── fenwick_2d.hpp │ ├── fenwick_range_update.hpp │ ├── fenwick_range_update_range_query.hpp │ ├── heap.hpp │ ├── meldable_heap.hpp │ ├── merge_sort_tree.hpp │ ├── monoids_lazy.hpp │ ├── nonintersecting_range_tree.hpp │ ├── offline_segment_tree_2d.hpp │ ├── rmq2d.hpp │ ├── segment_tree.hpp │ ├── segment_tree_lazy.hpp │ ├── set_lazy.hpp │ ├── sparse_table.hpp │ ├── sparse_table_disjoint.hpp │ ├── treap.hpp │ ├── treap_lazy.hpp │ └── wavelet_tree.hpp ├── dp_optimizations/ │ └── convex_hull_trick.hpp ├── geometry/ │ ├── dynamic_convex_hull.hpp │ ├── halfplane_intersection.hpp │ ├── point.hpp │ ├── polygon.hpp │ └── voronoi.hpp ├── graph/ │ ├── bcc.hpp │ ├── bipartite_coloring.hpp │ ├── bipartite_matching.hpp │ ├── dijkstra_vlog.hpp │ ├── directed_cactus.hpp │ ├── dsu.hpp │ ├── eppstein_shortest_paths.hpp │ ├── eulerian_paths.hpp │ ├── graph.hpp │ ├── hopcroft_karp.hpp │ ├── hungarian_algorithm.hpp │ ├── maxflow.hpp │ ├── mincost_circulation.hpp │ ├── mincost_flow.hpp │ ├── scc.hpp │ ├── st_numbering.hpp │ └── two_sat.hpp ├── math/ │ └── gauss_bitset.hpp ├── old_impl/ │ ├── data_structures/ │ │ ├── implicit_treap.hpp │ │ ├── implicit_treap_basic.hpp │ │ ├── max_count_segment_tree.cpp │ │ ├── merging_segment_tree.cpp │ │ ├── min_segment_tree.cpp │ │ ├── monotonous_queue.cpp │ │ ├── persistent_segment_tree.cpp │ │ ├── persistent_segment_tree_lazy.cpp │ │ ├── persistent_treap.cpp │ │ ├── persistent_treap_lazy.cpp │ │ ├── segment_tree.cpp │ │ ├── segment_tree_AP.cpp │ │ ├── segment_tree_add_mult.cpp │ │ ├── segment_tree_fast.cpp │ │ ├── segment_tree_lazy_min.cpp │ │ ├── segment_tree_lazy_sum.cpp │ │ ├── segment_tree_nonzero.cpp │ │ ├── segment_tree_with_binary_search.cpp │ │ └── treap.cpp │ ├── geometry/ │ │ ├── closest_points.cpp │ │ ├── convex_hull.cpp │ │ ├── dynamic_upper_hull.cpp │ │ ├── kd-tree.cpp │ │ └── rectangle_union.cpp │ ├── graph/ │ │ ├── dsu_bipartite.cpp │ │ ├── eulerian_path.cpp │ │ ├── max_anticlique.cpp │ │ ├── maximum_closure.cpp │ │ ├── mincost_maxflow.cpp │ │ ├── persistent_dsu.cpp │ │ ├── scc_tarjan.cpp │ │ └── st_numbering.cpp │ ├── math/ │ │ ├── combinatorics.cpp │ │ ├── fft.cpp │ │ ├── fft_mod.cpp │ │ ├── fft_xor.cpp │ │ ├── fft_xor_mod.cpp │ │ ├── gauss_elimination_equations.cpp │ │ ├── gauss_elimination_equations_mod.cpp │ │ ├── gauss_elimination_equations_mod_number_solutions.cpp │ │ ├── matrix_exponential.cpp │ │ └── number_theory.cpp │ ├── strings/ │ │ ├── aho_corasick.cpp │ │ ├── aho_corasick_dynamic.cpp │ │ ├── kmp.cpp │ │ ├── palindromic_tree.cpp │ │ ├── rabin_karp.cpp │ │ ├── suffix_array.cpp │ │ ├── suffix_array_hash.cpp │ │ ├── suffix_array_log2.cpp │ │ ├── suffix_automaton.cpp │ │ └── trie.cpp │ └── tree/ │ ├── centroid_decomposition.cpp │ ├── dsu_on_tree.cpp │ ├── hld.cpp │ ├── lca-seg3.cpp │ ├── link_cut_tree.cpp │ └── virtual_tree.cpp ├── other/ │ ├── bits/ │ │ ├── bit_trie.hpp │ │ └── xor_basis.hpp │ ├── dp_optimizations/ │ │ ├── LiChao_dynamic.cpp │ │ ├── LiChao_parabolic.cpp │ │ ├── LiChao_segment_tree_offline.cpp │ │ ├── convex_hull_trick_max.cpp │ │ ├── convex_hull_trick_min.cpp │ │ ├── divide_and_conquer_optimization.cpp │ │ ├── slope_trick.cpp │ │ └── slope_trick_priority_queue.cpp │ ├── queries/ │ │ ├── mo.cpp │ │ ├── mo_dsu.cpp │ │ ├── mo_online.cpp │ │ └── offline_centroid_queries.cpp │ └── utils/ │ └── count_inversions.cpp ├── strings/ │ ├── aho_corasick.hpp │ ├── hashing.hpp │ ├── suffix_array.hpp │ └── suffix_automaton.hpp └── tree/ ├── centroid_decomposition.hpp ├── euler_order_segment_tree.cpp ├── lca.hpp ├── lca_sparse_table.hpp ├── line_tree.hpp ├── link_cut_tree.hpp ├── vertex_add_path_sum.hpp └── virtual_tree.hpp ================================================ FILE CONTENTS ================================================ ================================================ FILE: README.md ================================================ # Coding-Library This is a collection of implementations of various data structures and algorithms, intended for competitive programming. Some of these implementations are relatively old, as they are from my IOI times, but might still be a useful point of reference. The suggested way to set this up is to create a directory "coding_library" somewhere (or a symlink to this repo), and add it to $CPLUS_INCLUDE_PATH. I plan on making a script that then expands the libraries that you use, but this is still a TODO. # Random Useful ideas, that aren't exactly a part of this library. 1) Bitset for almost arbitrary N: - https://codeforces.com/blog/entry/100910?#comment-896093 - https://codeforces.com/problemsets/acmsguru/problem/99999/415 2) MiniSat based SAT solver that can be used in competitive programming: - https://github.com/togatoga/togasat?tab=readme-ov-file ================================================ FILE: data_structures/clever_adding_intervals_set.hpp ================================================ #include using namespace std; template struct clever_set { map, T> value; void init(int n) { value[{n, 1}] = (T)0; } vector, T> > add(int l, int r, T val) { auto bg = value.lower_bound({l, 0})->first; if(bg.second != l) { T val = value[bg]; value.erase(bg); value[{l - 1, bg.second}] = val; value[{bg.first, l}] = val; } auto en = value.lower_bound({r, 0})->first; if(en.first != r) { T val = value[en]; value.erase(en); value[{en.first, r + 1}] = val; value[{r, en.second}] = val; } vector, T> > ret; auto itt = value.lower_bound({l, 0}); while(true) { if(itt == value.end() || itt->first.first > r) { break; } ret.push_back({{itt->first.second, itt->first.first}, itt->second}); ++itt; } for(auto it: ret) { value.erase({it.first.second, it.first.first}); } value[{r, l}] = val; return ret; } }; ================================================ FILE: data_structures/compressed_fenwick.hpp ================================================ #include #include using namespace std; template struct CompressedFenwick { Fenwick t; vector li; int get_idx(int x) { return lower_bound(li.begin(), li.end(), x) - li.begin() + 1; } void update(int x, T val) { t.update(get_idx(x), val); } void add_to_prep(int x) { li.push_back(x); } void prepare() { sort(li.begin(), li.end()); li.erase(unique(li.begin(), li.end()), li.end()); t.init(li.size() + 2); } T query(int x) { return t.query(get_idx(x) - 1); } T size() { return t.query(t.sz); } }; ================================================ FILE: data_structures/decremental_constant_set.hpp ================================================ #include #include using namespace std; /* The structures resembles a set on N positions that are said to initially be active, and supports the following updates: - Remove some active position from the set. - query_left(i) to find the first active position before i (inclusive). - query_right(i) to find the first active position after i (inclusive). Main idea is to do DSU on blocks of size w=64 working in O(N alpha(N) / w) = O(N) overall, and then answer small queries in O(1) using bitwise operations. Based on Nachia's implementation: https://codeforces.com/contest/2018/submission/283309295 */ class DecrementalConstantSet { private: const uint64_t FULL_MASK = ~0ull; int n, b; vector mask; vector large_block_left, large_block_right; DSU dsu; int small_query_prefix(int c, uint64_t filter_mask) { uint64_t z = mask[c] & filter_mask; return z ? (c << 6) + __builtin_ctzll(z) : -1; } int small_query_suffix(int c, uint64_t filter_mask) { uint64_t z = mask[c] & filter_mask; return z ? (c << 6) + 63 - __builtin_clzll(z) : -1; } public: DecrementalConstantSet(int _n) : n(_n + 2), b((n + 64) >> 6), mask(b, FULL_MASK), large_block_left(b + 1), large_block_right(b + 1), dsu(b) { iota(large_block_left.begin(), large_block_left.end(), 0); iota(large_block_right.begin(), large_block_right.end(), 0); } void remove(int _i) { // Indices are +1 int i = _i + 1; int c = i >> 6, d = i & 63; mask[c] &= ~(1ull << d); if(mask[c] == 0) { for(int dir: {-1, 1}) { if(c + dir < 0 || c + dir >= b || mask[c + dir]) { continue; } int root = dsu.root(c); int next_root = dsu.root(c + dir); if(root != next_root) { int new_root = dsu.unite(root, next_root); large_block_left[new_root] = min(large_block_left[root], large_block_left[next_root]); large_block_right[new_root] = max(large_block_right[root], large_block_right[next_root]); } } } } int query_right(int _i) { if(_i >= n) { return n; } // Indices are +1 and we undo when we return int i = max(_i, 0) + 1; int c = i >> 6, d = i & 63; if(d > 0) { int x = small_query_prefix(c, FULL_MASK << d); if(x >= 0) { return x - 1; } c++; } if(!mask[c]) { c = large_block_right[dsu.root(c)] + 1; } return small_query_prefix(c, FULL_MASK) - 1; } int query_left(int _i) { if(_i < 0) { return -1; } // Indices are +1 and we undo when we return int i = min(_i + 1, n); int c = i >> 6, d = i & 63; if(d < 63) { int x = small_query_suffix(c, (1ull << (d + 1)) - 1); if(x >= 0) { return x - 1; } c--; } if(!mask[c]) { c = large_block_left[dsu.root(c)] - 1; } return small_query_suffix(c, FULL_MASK) - 1; } }; ================================================ FILE: data_structures/fenwick.hpp ================================================ #include using namespace std; template class Fenwick { private: int sz, log_size; vector tr; public: void init(int n) { sz = n + 1; log_size = 31 - __builtin_clz(sz); tr.assign(sz + 1, 0); } void update(int idx, T val) { if(idx <= 0) { assert(false); return; } for(; idx <= sz; idx += (idx & -idx)) { tr[idx] += val; } } T query(int idx) { T ans = 0; for(; idx >= 1; idx -= (idx & -idx)) { ans += tr[idx]; } return ans; } T query(int l, int r) { return query(r) - query(l - 1); } int find_kth(T k) { int idx = 0; for(int i = log_size; i >= 0; i--) { if(idx + (1 << i) < sz && tr[idx + (1 << i)] < k) { k -= tr[idx + (1 << i)]; idx += (1 << i); } } return idx + 1; } }; ================================================ FILE: data_structures/fenwick_2d.hpp ================================================ #include using namespace std; template class Fenwick2d { private: int sz; vector> t; void update_row(int row, int idx, T val) { if(idx == 0) { return; } for(; idx <= sz; idx += (idx & -idx)) { if(t[row].find(idx) == t[row].end()) { t[row][idx] = merge(identity(), val); } else { t[row][idx] = merge(t[row][idx], val); } } } T query_row(int row, int idx) { T ans = identity(); for(; idx >= 1; idx -= (idx & -idx)) { if(t[row].find(idx) == t[row].end()) { ans = merge(identity(), ans); } else { ans = merge(t[row][idx], ans); } } return ans; } public: void init(int _sz) { sz = _sz; t.assign(sz + 1, unordered_map()); } void update(int row, int col, T val) { if(col == 0) { return; } for(; row <= sz; row += (row & -row)) { update_row(row, col, val); } } T query(int row, int col) { T ans = identity(); for(; row >= 1; row -= (row & -row)) { ans = merge(query_row(row, col), ans); } return ans; } }; // int min_custom(int a, int b) { return min(a, b); } // int max_custom(int a, int b) { return max(a, b); } // int sum_custom(int a, int b) { return a + b; } // int identity_min() { return INT_MAX; } // int identity_max() { return INT_MIN; } // int identity_sum() { return 0; } // Fenwick2d ft; ================================================ FILE: data_structures/fenwick_range_update.hpp ================================================ #include using namespace std; template class FenwickRangeUpdate { private: int sz; vector tr; void update(int idx, T val) { if(idx <= 0) { assert(false); return; } for(; idx <= sz; idx += (idx & -idx)) { tr[idx] += val; } } public: void init(int n) { sz = n + 1; tr.assign(sz + 1, 0); } T query(int idx) { T ans = 0; for(; idx >= 1; idx -= (idx & -idx)) { ans += tr[idx]; } return ans; } void update(int l, int r, T val) { update(l, val); update(r + 1, -val); } }; ================================================ FILE: data_structures/fenwick_range_update_range_query.hpp ================================================ #include #include "coding_library/data_structures/fenwick_range_update.hpp" using namespace std; template class FenwickRangeUpdateRangeQuery { int sz; FenwickRangeUpdate t0, t1; void init(int _sz) { sz = _sz; t0.init(sz + 1); t1.init(sz + 1); } void update(int l, int r, T val) { t0.update(l, r, val); t1.update(l, r, -(l - 1) * val); t1.update(r + 1, sz, (r - l + 1) * val); } T query(int idx) { return t0.query(idx) * (T)idx + t1.query(idx); } T query(int l, int r) { return query(r) - query(l - 1); } }; ================================================ FILE: data_structures/heap.hpp ================================================ #include using namespace std; template class Heap { private: vector heap_values; vector heap, pos_in_heap; void push_up(int id) { while(id > 0 && cmp(heap_values[heap[id]], heap_values[heap[(id - 1) / 2]])) { swap(heap[id], heap[(id - 1) / 2]); swap(pos_in_heap[heap[id]], pos_in_heap[heap[(id - 1) / 2]]); id = (id - 1) / 2; } } void push_down(int id) { while(2 * id + 1 < heap.size()) { int child = 2 * id + 1; if(child + 1 < heap.size() && cmp(heap_values[heap[child + 1]], heap_values[heap[child]])) { child++; } if(cmp(heap_values[heap[id]], heap_values[heap[child]])) { break; } swap(heap[id], heap[child]); swap(pos_in_heap[heap[id]], pos_in_heap[heap[child]]); id = child; } } public: Heap() { clear(); } void clear() { heap.clear(); heap_values.clear(); pos_in_heap.clear(); } int push(T val) { heap.push_back(heap_values.size()); pos_in_heap.push_back(heap.size() - 1); heap_values.push_back(val); push_up(heap.size() - 1); return heap_values.size() - 1; } T pop() { int ret_node = heap[0]; swap(pos_in_heap[ret_node], pos_in_heap[heap.back()]); swap(heap[0], heap[heap.size() - 1]); heap.pop_back(); pos_in_heap[ret_node] = -1; if(heap.size() > 0) { push_down(0); } return heap_values[ret_node]; } size_t size() { return heap.size(); } bool empty() { return heap.size() == 0; } T top() { return heap_values[heap[0]]; } int top_node() { return heap[0]; } void update(int node, T val) { int p = pos_in_heap[node]; bool is_push_down = cmp(heap_values[node], val); if(is_push_down) { heap_values[node] = val; push_down(p); } else { heap_values[node] = val; push_up(p); } } }; ================================================ FILE: data_structures/meldable_heap.hpp ================================================ #include using namespace std; template class MeldableHeap { private: static uint32_t rng() { static mt19937 static_rng(random_device{}()); return static_rng(); } struct Node { T key; Node *left, *right; Node(T _key) : key(_key), left(nullptr), right(nullptr) {} }; Node* merge(Node* a, Node* b) { if(!a) { return b; } if(!b) { return a; } if(a->key > b->key) { swap(a, b); } Node* q = new Node(a->key); if(rng() & 1) { q->left = merge(a->left, b); q->right = a->right; } else { q->left = a->left; q->right = merge(a->right, b); } return q; } pair pop(Node* a) { Node* head = new Node(a->key); Node* tail = merge(a->left, a->right); return {head, tail}; } public: Node* root; MeldableHeap() : root(nullptr) {} MeldableHeap(Node* _root) : root(_root) {} MeldableHeap copy() const { MeldableHeap new_heap; new_heap.root = root; return new_heap; } MeldableHeap merge(const MeldableHeap& other) { MeldableHeap new_heap; new_heap.root = merge(root, other.root); return new_heap; } friend MeldableHeap merge( const MeldableHeap& a, const MeldableHeap& b ) { return a.merge(b); } void push(T key) { Node* new_node = new Node(key); root = merge(root, new_node); } T pop() { assert(root); auto [head, tail] = pop(root); root = tail; return head->key; } T top() const { return root->key; } tuple, MeldableHeap> trio() const { return { root->key, MeldableHeap{root->left}, MeldableHeap{root->right} }; } bool empty() const { return root == nullptr; } bool operator<(const MeldableHeap& other) const { return top() < other.top(); } }; ================================================ FILE: data_structures/merge_sort_tree.hpp ================================================ #include using namespace std; // InnerOrderedSet should implement: // 1) insert(x), which adds one copy of x. // 2) erase(x), which removes one copy of x. // 3) count_leq(x), which gives the number of elements <= x. // // Example with a treap is given below. template class MergeSortTree { private: int n; vector nodes; void update_rec(int v, int tl, int tr, int pos, int y, int delta) { if(delta == 1) { nodes[v].insert(y, 1); } else if(delta == -1) { nodes[v].erase(y); } if(tl == tr) { return; } int tm = (tl + tr) / 2; if(pos <= tm) { update_rec(v * 2, tl, tm, pos, y, delta); } else { update_rec(v * 2 + 1, tm + 1, tr, pos, y, delta); } } int query_rec(int v, int tl, int tr, int ql, int qr, int k) { if(ql > tr || qr < tl) { return 0; } if(ql <= tl && tr <= qr) { return nodes[v].count_leq(k); } int tm = (tl + tr) / 2; return query_rec(v * 2, tl, tm, ql, qr, k) + query_rec(v * 2 + 1, tm + 1, tr, ql, qr, k); } public: void init(int _n) { n = _n; nodes.resize(4 * (n + 10)); } void update(int x, int y, int delta) { update_rec(1, 1, n, x, y, delta); } int query(int qxl, int qxr, int k) { return query_rec(1, 1, n, qxl, qxr, k); } int query(int qxl, int qxr, int qyl, int qyr) { return query_rec(1, 1, n, qxl, qxr, qyr) - query_rec(1, 1, n, qxl, qxr, qyl - 1); } }; // #include // int sum_merge(int a, int b) { return a + b; } // using CountTreap = Treap; // MergeSortTree st; ================================================ FILE: data_structures/monoids_lazy.hpp ================================================ #include using namespace std; template class MonoidMin { public: struct MinVal { T val; bool operator==(const MinVal& other) const { return val == other.val; } bool operator!=(const MinVal& other) const { return !(*this == other); } }; struct AddLazy { T add_val; bool operator==(const AddLazy& other) const { return add_val == other.add_val; } bool operator!=(const AddLazy& other) const { return !(*this == other); } }; static MinVal merge(MinVal a, MinVal b) { return {min(a.val, b.val)}; } static MinVal e() { return {numeric_limits::max()}; } static MinVal lazy_apply(AddLazy f, MinVal x) { return {x.val + f.add_val}; } static AddLazy lazy_merge(AddLazy a, AddLazy b) { return {a.add_val + b.add_val}; } static AddLazy lazy_init(MinVal _) { return {0}; } }; // SegmentTreeLazy< // MonoidMin::MinVal, // MonoidMin::merge, // MonoidMin::e, // MonoidMin::AddLazy, // MonoidMin::lazy_apply, // MonoidMin::lazy_merge, // MonoidMin::lazy_init> template class MonoidSum { public: using Sum = T; using AddLazy = T; static Sum merge(Sum a, Sum b) { return a + b; } static Sum e() { return 0; } static Sum lazy_apply(AddLazy f, Sum x) { return f + x; } static AddLazy lazy_merge(AddLazy a, AddLazy b) { return a + b; } static AddLazy lazy_init(Sum _) { return 0; } static Sum inverse(Sum x) { return -x; } }; // SegmentTreeLazy< // MonoidSum::Sum, // MonoidSum::merge, // MonoidSum::e, // MonoidSum::AddLazy, // MonoidSum::lazy_apply, // MonoidSum::lazy_merge, // MonoidSum::lazy_init> template class MonoidMinWithCount { public: struct MinWithCount { T min_val; int count; bool operator==(const MinWithCount& other) const { return min_val == other.min_val && count == other.count; } bool operator!=(const MinWithCount& other) const { return !(*this == other); } }; struct AddLazy { T add_val; bool operator==(const AddLazy& other) const { return add_val == other.add_val; } bool operator!=(const AddLazy& other) const { return !(*this == other); } }; static MinWithCount merge(MinWithCount a, MinWithCount b) { if(a.min_val < b.min_val) { return a; } if(b.min_val < a.min_val) { return b; } return {a.min_val, a.count + b.count}; } static MinWithCount e() { return {numeric_limits::max(), 0}; } static MinWithCount lazy_apply(AddLazy f, MinWithCount x) { return {x.min_val + f.add_val, x.count}; } static AddLazy lazy_merge(AddLazy a, AddLazy b) { return {a.add_val + b.add_val}; } static AddLazy lazy_init(MinWithCount _) { return {0}; } }; // SegmentTreeLazy< // MonoidMinWithCount::MinWithCount, // MonoidMinWithCount::merge, // MonoidMinWithCount::e, // MonoidMinWithCount::AddLazy, // MonoidMinWithCount::lazy_apply, // MonoidMinWithCount::lazy_merge, // MonoidMinWithCount::lazy_init> template class MonoidSumArithmeticProgression { struct Sum { T val; T l, r; bool operator==(const Sum& other) const { return val == other.val && l == other.l && r == other.r; } bool operator!=(const Sum& other) const { return !(*this == other); } }; struct AddLazy { T alpha; T beta; T l_border; bool operator==(const AddLazy& other) const { return alpha == other.alpha && beta == other.beta && l_border == other.l_border; } bool operator!=(const AddLazy& other) const { return !(*this == other); } }; static Sum merge(Sum a, Sum b) { return { a.val + b.val, a.l, b.r, }; } static Sum e() { return {0, 0}; } static Sum lazy_apply(AddLazy f, Sum x) { T delta = x.l - f.l_border; T len = x.r - x.l + 1; x.val += (delta * f.beta + f.alpha) * len + f.beta * len * (len + 1) / 2; return x; } static AddLazy lazy_merge(AddLazy a, AddLazy b) { T delta = b.l_border - a.l_border; b.alpha += a.alpha + delta * a.beta; b.beta += a.beta; return b; } static AddLazy lazy_init(Sum node) { return {0, 0, node.l}; } }; // SegmentTreeLazy< // MonoidSumArithmeticProgression::Sum, // MonoidSumArithmeticProgression::merge, // MonoidSumArithmeticProgression::e, // MonoidSumArithmeticProgression::AddLazy, // MonoidSumArithmeticProgression::lazy_apply, // MonoidSumArithmeticProgression::lazy_merge, // MonoidSumArithmeticProgression::lazy_init> ================================================ FILE: data_structures/nonintersecting_range_tree.hpp ================================================ #include using namespace std; /* Based on https://codeforces.com/contest/2063/problem/F2. Main idea is to do reverse small-to-large trick and we can store everything with arrays instead of using a complicated approach with sets and maps. This version only counts the "non-used" elements in the range, so we might want to redefine this in a different problem. */ class NonintersectingRangeTree { public: vector pnt, size, par, par_idx; vector used; NonintersectingRangeTree(int n) { pnt.assign(n + 2, 0); iota(pnt.begin(), pnt.end(), 1); par_idx.assign(n + 2, 0); par = {0}; size.assign(n + 2, 0); used.assign(n + 2, false); used[0] = true; pnt[0] = n + 2; pnt[n + 1] = n + 1; size[0] = n; } void add(int l, int r) { pnt[l] = r + 1; pnt[r] = r; used[l] = true; int p = get_parent(l); int out_ptr = p + 1, ins_ptr = l + 1; int out_size = 0, ins_size = 0; while(pnt[out_ptr] != out_ptr && pnt[ins_ptr] != ins_ptr) { out_size += !used[out_ptr]; ins_size += !used[ins_ptr]; out_ptr = pnt[out_ptr]; ins_ptr = pnt[ins_ptr]; } int upd_ptr, new_par_idx = par.size(); if(pnt[out_ptr] == out_ptr) { upd_ptr = p + 1; par.push_back(p); par[par_idx[l]] = l; ins_size = size[p] - 2 - out_size; size[p] = out_size; size[l] = ins_size; } else { upd_ptr = l + 1; par.push_back(l); out_size = size[p] - 2 - ins_size; size[p] = out_size; size[l] = ins_size; } while(pnt[upd_ptr] != upd_ptr) { par_idx[upd_ptr] = new_par_idx; upd_ptr = pnt[upd_ptr]; } } int get_parent(int x) { return par[par_idx[x]]; } }; ================================================ FILE: data_structures/offline_segment_tree_2d.hpp ================================================ #include #include using namespace std; template class OfflineSegmentTree2d { private: int n; vector> ys; vector> ft; void collect(int v, int tl, int tr, int pos, int y) { ys[v].push_back(y); if(tl == tr) { return; } int tm = (tl + tr) / 2; if(pos <= tm) { collect(v * 2, tl, tm, pos, y); } else { collect(v * 2 + 1, tm + 1, tr, pos, y); } } void build_compression(int v) { sort(ys[v].begin(), ys[v].end()); ys[v].erase(unique(ys[v].begin(), ys[v].end()), ys[v].end()); ft[v].init(ys[v].size() + 2); } void update_rec(int v, int tl, int tr, int pos, int y, T val) { if(ys[v].empty()) { return; } auto it = lower_bound(ys[v].begin(), ys[v].end(), y); if(it == ys[v].end() || *it != y) { return; } int rank = (it - ys[v].begin()) + 1; ft[v].update(rank, val); if(tl == tr) { return; } int tm = (tl + tr) / 2; if(pos <= tm) { update_rec(v * 2, tl, tm, pos, y, val); } else { update_rec(v * 2 + 1, tm + 1, tr, pos, y, val); } } T query_rec(int v, int tl, int tr, int l, int r, int yl, int yr) { if(l > tr || r < tl) { return 0; } if(l <= tl && tr <= r) { if(ys[v].empty()) { return 0; } auto itl = lower_bound(ys[v].begin(), ys[v].end(), yl); auto itr = upper_bound(itl, ys[v].end(), yr); int ly = (itl - ys[v].begin()) + 1; int ry = (itr - ys[v].begin()); return ft[v].query(ly, ry); } int tm = (tl + tr) / 2; return query_rec(v * 2, tl, tm, l, r, yl, yr) + query_rec(v * 2 + 1, tm + 1, tr, l, r, yl, yr); } public: void init(int _n) { n = _n; int tsz = 4 * (n + 10); ys.assign(tsz, {}); ft.resize(tsz); } void prepare_update(int x, int y) { collect(1, 1, n, x, y); } void prepare() { for(int v = 1; v < 4 * (n + 10); ++v) { if(!ys[v].empty()) { build_compression(v); } } } void update(int x, int y, T val) { update_rec(1, 1, n, x, y, val); } T query(int xl, int xr, int yl, int yr) { return query_rec(1, 1, n, xl, xr, yl, yr); } }; ================================================ FILE: data_structures/rmq2d.hpp ================================================ #include using namespace std; struct rmq1d { vector rmq; int n; void init(int N) { n = N; rmq.resize(4 * n); } void add(int v, int tl, int tr, int x) { ++rmq[v]; if(tl + 1 == tr) { return; } int m = (tl + tr) >> 1; if(x < m) { add(v * 2 + 1, tl, m, x); } else { add(v * 2 + 2, m, tr, x); } } void add(int x) { add(0, 0, n, x); } int get(int v, int tl, int tr, int l, int r) { if(r <= tl || tr <= l) { return 0; } if(l <= tl && tr <= r) { return rmq[v]; } int m = (tl + tr) >> 1; return get(v * 2 + 1, tl, m, l, r) + get(v * 2 + 2, m, tr, l, r); } int get(int l, int r) { return get(0, 0, n, l, r); } }; struct rmq2d { vector rmq; vector > sv; int n; void init(int N) { n = N; sv.resize(4 * n); rmq.resize(4 * n); } void prep(int v, int tl, int tr, int x, int y) { sv[v].push_back(y); if(tl + 1 == tr) { return; } int m = (tl + tr) >> 1; if(x < m) { prep(v * 2 + 1, tl, m, x, y); } else { prep(v * 2 + 2, m, tr, x, y); } } void prep(int x, int y) { prep(0, 0, n, x, y); } void add(int v, int tl, int tr, int x, int y) { int k = lower_bound(sv[v].begin(), sv[v].end(), y) - sv[v].begin(); rmq[v].add(k); if(tl + 1 == tr) { return; } int m = (tl + tr) >> 1; if(x < m) { add(v * 2 + 1, tl, m, x, y); } else { add(v * 2 + 2, m, tr, x, y); } } void add(int x, int y) { add(0, 0, n, x, y); } void build(int v, int tl, int tr) { sort(sv[v].begin(), sv[v].end()); rmq[v].init(sv[v].size()); if(tl + 1 == tr) { return; } int m = (tl + tr) >> 1; build(v * 2 + 1, tl, m); build(v * 2 + 2, m, tr); } void init2() { build(0, 0, n); } int get(int v, int tl, int tr, int l1, int r1, int l2, int r2) { if(r1 <= tl || tr <= l1) { return 0; } if(l1 <= tl && tr <= r1) { l2 = lower_bound(sv[v].begin(), sv[v].end(), l2) - sv[v].begin(); r2 = lower_bound(sv[v].begin(), sv[v].end(), r2) - sv[v].begin(); return rmq[v].get(l2, r2); } int m = (tl + tr) >> 1; return get(v * 2 + 1, tl, m, l1, r1, l2, r2) + get(v * 2 + 2, m, tr, l1, r1, l2, r2); } int get(int l1, int r1, int l2, int r2) { return get(0, 0, n, l1, r1, l2, r2); } }; ================================================ FILE: data_structures/segment_tree.hpp ================================================ #include using namespace std; // Motivated by atcoder library, but adapted to my style. All ranges are // inclusive in this implementation. // https://atcoder.github.io/ac-library/production/document_en/segtree.html template class SegmentTree { private: int n, size; vector tr; void pull(int x) { tr[x] = merge(tr[2 * x], tr[2 * x + 1]); } public: SegmentTree() { init(vector()); } SegmentTree(int _n) { init(vector(_n, e())); } SegmentTree(const vector& _a) { init(_a); } void init(const vector& _a) { n = _a.size(); size = 1; while(size < n) { size <<= 1; } tr.assign(2 * size, e()); for(int i = 0; i < n; i++) { tr[size + i] = _a[i]; } for(int i = size - 1; i > 0; i--) { pull(i); } } void update(int pos, T val) { pos += size; tr[pos] = val; for(pos >>= 1; pos > 0; pos >>= 1) { pull(pos); } } T get_pos(int pos) { return tr[pos + size]; } T query(int l, int r) { T ansl = e(), ansr = e(); for(l += size, r += size + 1; l < r; l >>= 1, r >>= 1) { if(l & 1) { ansl = merge(ansl, tr[l++]); } if(r & 1) { ansr = merge(tr[--r], ansr); } } return merge(ansl, ansr); } T query_all() { return tr[1]; } template int max_right(int l) const { return max_right(l, [](T x) { return f(x); }); } template int max_right(int l, F f) const { if(l == n) { return n; } l += size; T sm = e(); do { while(l % 2 == 0) { l >>= 1; } if(!f(merge(sm, tr[l]))) { while(l < size) { l = (2 * l); if(f(merge(sm, tr[l]))) { sm = merge(sm, tr[l]); l++; } } return l - size; } sm = merge(sm, tr[l]); l++; } while((l & -l) != l); return n; } template int min_left(int r) const { return min_left(r, [](T x) { return f(x); }); } template int min_left(int r, F f) const { if(r == -1) { return 0; } r += size + 1; T sm = e(); do { r--; while(r > 1 && (r % 2)) { r >>= 1; } if(!f(merge(tr[r], sm))) { while(r < size) { r = (2 * r + 1); if(f(merge(tr[r], sm))) { sm = merge(tr[r], sm); r--; } } return r + 1 - size; } sm = merge(tr[r], sm); } while((r & -r) != r); return 0; } }; // int min_custom(int a, int b) { return min(a, b); } // int min_e() { return INT_MAX; } // int max_custom(int a, int b) { return max(a, b); } // int max_e() { return INT_MIN; } ================================================ FILE: data_structures/segment_tree_lazy.hpp ================================================ #include using namespace std; // Motivated by atcoder library, but adapted to my style. All ranges are // inclusive in this implementation. // https://atcoder.github.io/ac-library/production/document_en/segtree.html // // Another difference is that I support a callback from the tree node to // the lazy node, which is useful when we want to maintain a push that is // not uniform across the left and right child (arithmetic progression add). template< class T, T (*merge)(T, T), T (*e)(), class G, T (*lazy_apply)(G, T), G (*lazy_merge)(G, G), G (*lazy_init)(T)> class SegmentTreeLazy { private: int n, size, log_size; vector tr; vector lazy; void pull(int x) { tr[x] = merge(tr[2 * x], tr[2 * x + 1]); } void push_one(int x, G f) { tr[x] = lazy_apply(f, tr[x]); if(x < size) { lazy[x] = lazy_merge(f, lazy[x]); } } void push(int x) { push_one(2 * x, lazy[x]); push_one(2 * x + 1, lazy[x]); lazy[x] = lazy_init(tr[x]); } void push_all_down(int x) { for(int i = log_size; i >= 1; i--) { push(x >> i); } } void push_all_open_range(int l, int r) { for(int i = log_size; i >= 1; i--) { if(((l >> i) << i) != l) { push(l >> i); } if(((r >> i) << i) != r) { push((r - 1) >> i); } } } public: SegmentTreeLazy() { init(vector()); } SegmentTreeLazy(int _n) { init(vector(_n, e())); } SegmentTreeLazy(const vector &_a) { init(_a); } void init(const vector &_a) { n = _a.size(); size = 1; log_size = 0; while(size < n) { size <<= 1; log_size++; } tr.assign(2 * size, e()); lazy.resize(size); for(int i = 0; i < n; i++) { tr[size + i] = _a[i]; } for(int i = size - 1; i > 0; i--) { pull(i); lazy[i] = lazy_init(tr[i]); } } void update(int pos, T val) { pos += size; push_all_down(pos); tr[pos] = val; for(pos >>= 1; pos > 0; pos >>= 1) { pull(pos); } } void apply_lazy(int l, int r, G f) { if(l > r) { return; } l += size, r += size + 1; push_all_open_range(l, r); for(int l0 = l, r0 = r; l0 < r0; l0 >>= 1, r0 >>= 1) { if(l0 & 1) { push_one(l0++, f); } if(r0 & 1) { push_one(--r0, f); } } for(int i = 1; i <= log_size; i++) { if(((l >> i) << i) != l) { pull(l >> i); } if(((r >> i) << i) != r) { pull((r - 1) >> i); } } } T get_pos(int pos) { pos += size; push_all_down(pos); return tr[pos]; } T query(int l, int r) { T ansl = e(), ansr = e(); l += size, r += size + 1; push_all_open_range(l, r); for(; l < r; l >>= 1, r >>= 1) { if(l & 1) { ansl = merge(ansl, tr[l++]); } if(r & 1) { ansr = merge(tr[--r], ansr); } } return merge(ansl, ansr); } T query_all() { return tr[1]; } template int max_right(int l) const { return max_right(l, [](T x) { return f(x); }); } template int max_right(int l, F f) const { if(l == n) { return n; } l += size; push_all_down(l); T sm = e(); do { while(l % 2 == 0) { l >>= 1; } if(!f(merge(sm, tr[l]))) { while(l < size) { push(l); l = (2 * l); if(f(merge(sm, tr[l]))) { sm = merge(sm, tr[l]); l++; } } return l - size; } sm = merge(sm, tr[l]); l++; } while((l & -l) != l); return n; } template int min_left(int r) const { return min_left(r, [](T x) { return f(x); }); } template int min_left(int r, F f) const { if(r == -1) { return 0; } r += size + 1; push_all_down(r - 1); T sm = e(); do { r--; while(r > 1 && (r % 2)) { r >>= 1; } if(!f(merge(tr[r], sm))) { while(r < size) { push(r); r = (2 * r + 1); if(f(merge(tr[r], sm))) { sm = merge(tr[r], sm); r--; } } return r + 1 - size; } sm = merge(tr[r], sm); } while((r & -r) != r); return 0; } }; ================================================ FILE: data_structures/set_lazy.hpp ================================================ #include using namespace std; template class Container = multiset> class SetLazy : private Container { private: T lazy_value = T(); class Iterator { private: typename Container::iterator it; const T& lazy_value; public: Iterator(typename Container::iterator it, const T& lazy_value) : it(it), lazy_value(lazy_value) {} T operator*() const { return *it + lazy_value; } Iterator& operator++() { ++it; return *this; } Iterator operator++(int) { Iterator tmp = *this; ++it; return tmp; } bool operator==(const Iterator& other) const { return it == other.it; } bool operator!=(const Iterator& other) const { return it != other.it; } typename Container::iterator base() const { return it; } }; public: void insert(const T& value) { Container::insert(value - lazy_value); } void erase(const T& value) { Container::erase(value - lazy_value); } void erase(Iterator it) { Container::erase(it.base()); } void add_all(const T& x) { lazy_value += x; } T get_lazy_value() const { return lazy_value; } bool count(const T& value) const { return Container::find(value - lazy_value) != Container::end(); } Iterator find(const T& value) { auto it = Container::find(value - lazy_value); return it != Container::end() ? Iterator(it, lazy_value) : end(); } Iterator lower_bound(const T& value) { return Iterator( Container::lower_bound(value - lazy_value), lazy_value ); } Iterator upper_bound(const T& value) { return Iterator( Container::upper_bound(value - lazy_value), lazy_value ); } Iterator begin() { return Iterator(Container::begin(), lazy_value); } Iterator end() { return Iterator(Container::end(), lazy_value); } const Iterator begin() const { return Iterator(Container::begin(), lazy_value); } const Iterator end() const { return Iterator(Container::end(), lazy_value); } using Container::size; using Container::empty; void merge(const SetLazy& other) { for(const auto& value: other) { insert(value); } } void print() const { std::cout << "{"; for(const auto& value: *this) { std::cout << value << ", "; } std::cout << "}" << std::endl; } }; /* SetLazy multiset_lazy // Uses multiset by default SetLazy set_lazy; // Uses set explicitly */ ================================================ FILE: data_structures/sparse_table.hpp ================================================ #include using namespace std; template class SparseTable { private: int n; vector> dp; vector prec_lg2; public: SparseTable() { n = 0; dp.clear(); prec_lg2.clear(); } void init(const vector& a) { n = a.size(); prec_lg2.resize(n + 1); for(int i = 2; i <= n; i++) { prec_lg2[i] = prec_lg2[i >> 1] + 1; } dp.assign(prec_lg2[n] + 1, vector(n)); dp[0] = a; for(int j = 1; (1 << j) <= n; j++) { for(int i = 0; i + (1 << j) <= n; i++) { dp[j][i] = merge(dp[j - 1][i], dp[j - 1][i + (1 << (j - 1))]); } } } T query(int l, int r) { int k = prec_lg2[r - l + 1]; return merge(dp[k][l], dp[k][r - (1 << k) + 1]); } }; // int min_custom(int a, int b) { return min(a, b); } // SparseTable tbl; ================================================ FILE: data_structures/sparse_table_disjoint.hpp ================================================ #include using namespace std; template class SparseTableDisjoint { private: int n; vector prec_lg2, mask; vector> dp; vector a; void init_dnc(int l, int r, int lvl) { if(l == r) { dp[lvl][l] = a[l]; return; } int m = (l + r) >> 1; init_dnc(l, m, lvl + 1); init_dnc(m + 1, r, lvl + 1); dp[lvl][m] = a[m]; for(int i = m - 1; i >= l; i--) { dp[lvl][i] = merge(a[i], dp[lvl][i + 1]); } dp[lvl][m + 1] = a[m + 1]; mask[m + 1] |= 1 << lvl; for(int i = m + 2; i <= r; i++) { dp[lvl][i] = merge(dp[lvl][i - 1], a[i]); mask[i] |= 1 << lvl; } } public: SparseTableDisjoint() { n = 0; a.clear(); dp.clear(); prec_lg2.clear(); mask.clear(); } void init(const vector& _a) { a = _a; n = a.size(); prec_lg2.assign(4 * n + 1, 0); for(int i = 2; i <= 4 * n; i++) { prec_lg2[i] = prec_lg2[i >> 1] + 1; } dp.assign(prec_lg2[n] + 2, vector(n)); mask.assign(n, 0); init_dnc(0, n - 1, 0); } T query(int l, int r) { if(l == r) { return a[l]; } int mask_diff = mask[l] ^ mask[r]; int k = prec_lg2[mask_diff & -mask_diff]; return merge(dp[k][l], dp[k][r]); } }; // int min_custom(int a, int b) { return min(a, b); } // sparse_table_disjoint st; ================================================ FILE: data_structures/treap.hpp ================================================ #include using namespace std; template struct TreapNode { KeyT key; T data, subtree; uint64_t prior; size_t size; TreapNode *left, *right; TreapNode(KeyT key, T data) : key(key), data(data), left(nullptr), right(nullptr), size(1) { prior = rng(); } void pull() { subtree = data; size = 1; if(left) { subtree = merge_func(left->subtree, subtree); size += left->size; } if(right) { subtree = merge_func(subtree, right->subtree); size += right->size; } } friend pair split(TreapNode* t, KeyT key) { if(!t) { return {nullptr, nullptr}; } if(key < t->key) { auto [left, t_left] = split(t->left, key); t->left = t_left; t->pull(); return {left, t}; } else { auto [t_right, right] = split(t->right, key); t->right = t_right; t->pull(); return {t, right}; } } friend pair split_by_size( TreapNode* t, size_t size ) { if(!t) { return {nullptr, nullptr}; } size_t left_size = t->left ? t->left->size : 0; if(left_size >= size) { auto [left, t_left] = split_by_size(t->left, size); t->left = t_left; t->pull(); return {left, t}; } else { auto [t_right, right] = split_by_size(t->right, size - 1 - left_size); t->right = t_right; t->pull(); return {t, right}; } } friend TreapNode* merge(TreapNode* l, TreapNode* r) { if(!l || !r) { return l ? l : r; } else if(l->prior > r->prior) { l->right = merge(l->right, r); l->pull(); return l; } else { r->left = merge(l, r->left); r->pull(); return r; } } friend TreapNode* unordered_merge(TreapNode* l, TreapNode* r) { if(!l) { return r; } if(!r) { return l; } if(l->prior < r->prior) { swap(l, r); } auto [t1, t2] = split(r, l->key); l->left = unordered_merge(l->left, t1); l->right = unordered_merge(l->right, t2); l->pull(); return l; } friend void insert_in(TreapNode*& t, TreapNode* it) { if(!t) { t = it; } else if(it->prior > t->prior) { auto [t1, t2] = split(t, it->key); it->left = t1; it->right = t2; t = it; } else { insert_in(it->key < t->key ? t->left : t->right, it); } t->pull(); } friend TreapNode* erase_from( TreapNode*& t, KeyT key, bool delete_node = false ) { T return_data; if(t->key == key) { auto tmp = t; t = merge(t->left, t->right); return_data = tmp->data; if(delete_node) { delete tmp; return_data = nullptr; } } else { return_data = erase_from(key < t->key ? t->left : t->right, key, delete_node); } if(t) { t->pull(); } return return_data; } }; template class Treap { public: static uint64_t rng() { static mt19937_64 static_rng(random_device{}()); return static_rng(); } using Node = TreapNode; void _pull_all(Node* t) { if(t) { _pull_all(t->left); _pull_all(t->right); t->pull(); } } Node* root; Treap() { root = nullptr; } Treap(const vector>& a) { build_cartesian_tree(a); } void build_cartesian_tree(const vector>& a) { vector st; function recycle_stack = [&](Node* last) { Node* new_last = st.back(); st.pop_back(); new_last->right = last; return new_last; }; for(const auto& [key, val]: a) { Node* new_node = new Node(key, val); Node* last = nullptr; while(!st.empty() && st.back()->prior < new_node->prior) { last = recycle_stack(last); } new_node->left = last; st.push_back(new_node); } root = nullptr; while(!st.empty()) { root = recycle_stack(root); } _pull_all(root); } void insert(KeyT key, T data) { Node* new_node = new Node(key, data); insert_in(root, new_node); } Node* erase(KeyT key) { return erase_from(root, key); } friend Treap merge_treaps( Treap l, Treap r ) { Treap res; res.root = unordered_merge(l.root, r.root); return res; } int count_leq(KeyT max_key) { int cnt = 0; Node* cur = root; while(cur) { if(cur->key <= max_key) { cnt += (cur->left ? cur->left->size : 0) + 1; cur = cur->right; } else { cur = cur->left; } } return cnt; } }; // pair plus_func( // pair a, pair b // ) { // return {a.first + b.first, a.second + b.second}; // } // using TreapWithCount = Treap, plus_func>; // using Node = TreapWithCount::Node; // pair split_by_count(Node* t, int64_t k) { // if(!t) { // return {nullptr, nullptr}; // } // if(t->left && t->left->subtree.first >= k) { // auto [left, t_left] = split_by_count(t->left, k); // t->left = t_left; // t->pull(); // return {left, t}; // } else { // k -= (t->left ? t->left->subtree.first : 0); // if(k < t->data.first) { // Node* new_left = new Node(t->key, {k, k * t->key}); // t->data.first -= k; // t->data.second = t->data.first * t->key; // insert_in(t->left, new_left); // new_left = t->left; // t->left = nullptr; // t->pull(); // return {new_left, t}; // } // auto [t_right, new_right] = split_by_count(t->right, k - // t->data.first); t->right = t_right; t->pull(); return {t, new_right}; // } // } ================================================ FILE: data_structures/treap_lazy.hpp ================================================ #include using namespace std; template< class KeyT, class T, T (*merge_func)(T, T), class LazyT, uint64_t (*rng)()> struct TreapNode { KeyT key; T data, subtree; uint64_t prior; size_t size; TreapNode *left, *right; LazyT lazy; TreapNode(KeyT key, T data) : key(key), data(data), left(nullptr), right(nullptr), size(1) { prior = rng(); lazy = LazyT(); } void pull() { subtree = data; size = 1; if(left) { left->push(); subtree = merge_func(left->subtree, subtree); size += left->size; } if(right) { right->push(); subtree = merge_func(subtree, right->subtree); size += right->size; } } void push() { lazy.apply_lazy(this); } friend void push_lazy(TreapNode* t) { if(t) { t->push(); } } friend pair split(TreapNode* t, KeyT key) { if(!t) { return {nullptr, nullptr}; } t->push(); if(key < t->key) { auto [left, t_left] = split(t->left, key); t->left = t_left; t->pull(); return {left, t}; } else { auto [t_right, right] = split(t->right, key); t->right = t_right; t->pull(); return {t, right}; } } friend pair split_by_size( TreapNode* t, size_t size ) { if(!t) { return {nullptr, nullptr}; } t->push(); size_t left_size = t->left ? t->left->size : 0; if(left_size >= size) { auto [left, t_left] = split_by_size(t->left, size); t->left = t_left; t->pull(); return {left, t}; } else { auto [t_right, right] = split_by_size(t->right, size - 1 - left_size); t->right = t_right; t->pull(); return {t, right}; } } friend TreapNode* merge(TreapNode* l, TreapNode* r) { push_lazy(l); push_lazy(r); if(!l || !r) { return l ? l : r; } else if(l->prior > r->prior) { l->right = merge(l->right, r); l->pull(); return l; } else { r->left = merge(l, r->left); r->pull(); return r; } } friend TreapNode* unordered_merge(TreapNode* l, TreapNode* r) { push_lazy(l); push_lazy(r); if(!l) { return r; } if(!r) { return l; } if(l->prior < r->prior) { swap(l, r); } auto [t1, t2] = split(r, l->key); l->left = unordered_merge(l->left, t1); l->right = unordered_merge(l->right, t2); l->pull(); return l; } friend void insert_in(TreapNode*& t, TreapNode* it) { if(!t) { t = it; } else { t->push(); if(it->prior > t->prior) { auto [t1, t2] = split(t, it->key); it->left = t1; it->right = t2; t = it; } else { insert_in(it->key < t->key ? t->left : t->right, it); } } t->pull(); } friend TreapNode* erase_from( TreapNode*& t, KeyT key, bool delete_node = false ) { t->push(); T return_data; if(t->key == key) { auto tmp = t; t = merge(t->left, t->right); return_data = tmp->data; if(delete_node) { delete tmp; } } else { return_data = erase_from(key < t->key ? t->left : t->right, key, delete_node); } if(t) { t->pull(); } return return_data; } }; template class Treap { public: static uint64_t rng() { static mt19937_64 static_rng(random_device{}()); // FOR DEBUG: // static mt19937_64 static_rng(42); return static_rng(); } using Node = TreapNode; void _pull_all(Node* t) { if(t) { t->push(); _pull_all(t->left); _pull_all(t->right); t->pull(); } } Node* root; Treap() { root = nullptr; } Treap(const vector>& a) { build_cartesian_tree(a); } void build_cartesian_tree(const vector>& a) { vector st; function recycle_stack = [&](Node* last) { Node* new_last = st.back(); st.pop_back(); new_last->right = last; return new_last; }; for(const auto& [key, val]: a) { Node* new_node = new Node(key, val); Node* last = nullptr; while(!st.empty() && st.back()->prior < new_node->prior) { last = recycle_stack(last); } new_node->left = last; st.push_back(new_node); } root = nullptr; while(!st.empty()) { root = recycle_stack(root); } _pull_all(root); } void insert(KeyT key, T data) { Node* new_node = new Node(key, data); insert_in(root, new_node); } void erase(KeyT key) { return erase_from(root, key); } friend Treap merge_treaps( Treap l, Treap r ) { Treap res; res.root = unordered_merge(l.root, r.root); return res; } }; // template // struct ReverseLazy { // bool should_reverse; // ReverseLazy() { should_reverse = false; } // template // void apply_lazy(TreapNode* node) { // if(!node || !should_reverse) { // return; // } // swap(node->left, node->right); // if(node->left) { // node->left->lazy.should_reverse ^= true; // } // if(node->right) { // node->right->lazy.should_reverse ^= true; // } // should_reverse = false; // } // }; // struct EmptyMonoid { // static EmptyMonoid merge(EmptyMonoid a, EmptyMonoid b) { // return EmptyMonoid(); // } // }; // template // struct AddLazy { // T add_key = 0; // T add_data = 0; // template // void apply_lazy(TreapNode, T, merge_func, AddLazy, rng>* node) // { // if(!node || (add_key == 0 && add_data == 0)) { // return; // } // node->key.first += add_key; // node->data += add_data; // node->subtree += add_data * (T)node->size; // if(node->left) { // node->left->lazy.add_data += add_data; // node->left->lazy.add_key += add_key; // } // if(node->right) { // node->right->lazy.add_data += add_data; // node->right->lazy.add_key += add_key; // } // add_key = 0; // add_data = 0; // } // }; // int64_t add(int64_t a, int64_t b) { return a + b; } // using TreapWithLazy = Treap, int64_t, add, // AddLazy>; using Node = TreapWithLazy::Node; // Tested on https://codeforces.com/contest/702/problem/F. // https://codeforces.com/contest/702/submission/283296920 // https://codeforces.com/problemsets/acmsguru/submission/99999/294488144 ================================================ FILE: data_structures/wavelet_tree.hpp ================================================ #include using namespace std; // wvlt = new WaveletTree(); // wvlt->init(arr, 0, n); // // All queries are 1-indexed. class WaveletTree { private: int lo{1}, hi{0}; WaveletTree *left{nullptr}, *right{nullptr}; vector b; int psz{0}; public: WaveletTree() = default; void init(const vector& arr, int x, int y) { lo = x; hi = y; if(lo == hi || arr.empty()) { return; } int mid = (lo + hi) >> 1; auto f = [mid](int x) { return x <= mid; }; b.resize(arr.size() + 1); b[0] = 0; for(size_t i = 0; i < arr.size(); ++i) { b[i + 1] = b[i] + f(arr[i]); } psz = arr.size(); // Create a mutable copy of the array vector arr_copy(arr); auto pivot = stable_partition(arr_copy.begin(), arr_copy.end(), f); left = new WaveletTree(); right = new WaveletTree(); left->init(vector(arr_copy.begin(), pivot), lo, mid); right->init(vector(pivot, arr_copy.end()), mid + 1, hi); } int kth(int l, int r, int k) const { if(l > r) { return 0; } if(lo == hi) { return lo; } int inLeft = b[r] - b[l - 1], lb = b[l - 1], rb = b[r]; if(k <= inLeft) { return left->kth(lb + 1, rb, k); } return right->kth(l - lb, r - rb, k - inLeft); } int LTE(int l, int r, int k) const { if(l > r || k < lo) { return 0; } if(hi <= k) { return r - l + 1; } int lb = b[l - 1], rb = b[r]; return left->LTE(lb + 1, rb, k) + right->LTE(l - lb, r - rb, k); } int count(int l, int r, int k) const { if(l > r || k < lo || k > hi) { return 0; } if(lo == hi) { return r - l + 1; } int lb = b[l - 1], rb = b[r]; int mid = (lo + hi) >> 1; if(k <= mid) { return left->count(lb + 1, rb, k); } return right->count(l - lb, r - rb, k); } }; ================================================ FILE: dp_optimizations/convex_hull_trick.hpp ================================================ #include using namespace std; template class ConvexHullTrick { public: static constexpr T inf = is_integral_v ? numeric_limits::max() : numeric_limits::infinity(); T div(T a, T b) { if constexpr(is_integral_v) { return a / b - ((a ^ b) < 0 && a % b); } else { return a / b; } } struct Line { mutable T k, m, p; bool operator<(const Line& o) const { return k < o.k; } bool operator<(T x) const { return p < x; } }; multiset> hull; using Iter = typename multiset>::iterator; bool intersect(Iter x, Iter y) { if(y == hull.end()) { return x->p = inf, 0; } if(x->k == y->k) { x->p = x->m > y->m ? inf : -inf; } else { x->p = div(y->m - x->m, x->k - y->k); } return x->p >= y->p; } void add(T k, T m) { if constexpr(!maximum) { k = -k; m = -m; } auto z = hull.insert({k, m, 0}), y = z++, x = y; while(intersect(y, z)) { z = hull.erase(z); } if(x != hull.begin() && intersect(--x, y)) { intersect(x, y = hull.erase(y)); } while((y = x) != hull.begin() && (--x)->p >= y->p) { intersect(x, hull.erase(y)); } } T query(T x) { assert(!hull.empty()); auto l = *hull.lower_bound(x); T res = l.k * x + l.m; if constexpr(!maximum) { res = -res; } return res; } }; ================================================ FILE: geometry/dynamic_convex_hull.hpp ================================================ #include #include using namespace std; // Tested on problem 277 from SGU: // https://codeforces.com/problemsets/acmsguru/problem/99999/277 class DynamicConvexHull { public: set lower; set upper; private: coord_t lower_sum = 0; coord_t upper_sum = 0; using Iter = set::iterator; void add_to_hull(set& hull, coord_t& sum, const Point& p, int sign) { if(hull.empty()) { hull.insert(p); return; } auto right = hull.lower_bound(p); if(right != hull.end() && right->x == p.x) { if(sign * (p.y - right->y) >= 0) { return; } Iter left = (right != hull.begin()) ? prev(right) : hull.end(); Iter right_next = next(right); if(left != hull.end()) { sum -= (*left) ^ (*right); } if(right_next != hull.end()) { sum -= (*right) ^ (*right_next); } if(left != hull.end() && right_next != hull.end()) { sum += (*left) ^ (*right_next); } hull.erase(right); right = right_next; } Iter left = (right != hull.begin()) ? prev(right) : hull.end(); if(left != hull.end() && right != hull.end()) { if(sign * ccw(*left, *right, p) >= 0) { return; } sum -= (*left) ^ (*right); } while(left != hull.end() && left != hull.begin()) { Iter left_left = prev(left); if(sign * ccw(*left_left, *left, p) > 0) { break; } sum -= (*left_left) ^ (*left); hull.erase(left); left = left_left; } while(right != hull.end()) { Iter right_next = next(right); if(right_next == hull.end()) { break; } if(sign * ccw(p, *right, *right_next) > 0) { break; } sum -= (*right) ^ (*right_next); hull.erase(right); right = right_next; } if(left != hull.end()) { sum += (*left) ^ p; } if(right != hull.end()) { sum += p ^ (*right); } hull.insert(p); } public: DynamicConvexHull() = default; void add(const Point& p) { add_to_hull(lower, lower_sum, p, 1); add_to_hull(upper, upper_sum, p, -1); } coord_t doubled_area() const { if(lower.empty() || upper.empty()) { return 0; } coord_t result = lower_sum - upper_sum; const Point& right_lower = *lower.rbegin(); const Point& right_upper = *upper.rbegin(); if(!(right_lower == right_upper)) { result += right_lower ^ right_upper; } const Point& left_lower = *lower.begin(); const Point& left_upper = *upper.begin(); if(!(left_lower == left_upper)) { result += left_upper ^ left_lower; } return result; } }; ================================================ FILE: geometry/halfplane_intersection.hpp ================================================ #include #include using namespace std; using Line = pair; class HalfPlaneIntersection { private: vector lines; deque dq; bool empty_intersection = false; Point dir(int i) const { return lines[i].second - lines[i].first; } bool outside(int i, const Point& pt) const { return ccw(lines[i].first, lines[i].second, pt) < 0; } Point inter(int i, int j) const { return line_line_intersection( lines[i].first, lines[i].second, lines[j].first, lines[j].second ); } bool is_parallel(int i, int j) const { return abs(dir(i) ^ dir(j)) < Point::eps; } bool same_direction(int i, int j) const { return (dir(i) * dir(j)) > 0; } public: static vector sort_by_angle(const vector& lines) { vector sorted = lines; sort(sorted.begin(), sorted.end(), [](const Line& a, const Line& b) { return (a.second - a.first).angle() < (b.second - b.first).angle(); }); return sorted; } HalfPlaneIntersection(const vector& lines, bool is_sorted = false) : lines(is_sorted ? lines : sort_by_angle(lines)) { int n = this->lines.size(); for(int i = 0; i < n; i++) { while(dq.size() > 1 && outside(i, inter(dq.back(), dq[dq.size() - 2]))) { dq.pop_back(); } while(dq.size() > 1 && outside(i, inter(dq.front(), dq[1]))) { dq.pop_front(); } if(!dq.empty() && is_parallel(i, dq.back())) { if(!same_direction(i, dq.back())) { empty_intersection = true; return; } if(outside(i, this->lines[dq.back()].first)) { dq.pop_back(); } else { continue; } } dq.push_back(i); } while(dq.size() > 2 && outside(dq.front(), inter(dq.back(), dq[dq.size() - 2]))) { dq.pop_back(); } while(dq.size() > 2 && outside(dq.back(), inter(dq.front(), dq[1]))) { dq.pop_front(); } if(dq.size() < 3) { empty_intersection = true; } } bool is_non_empty() const { return !empty_intersection; } vector get_polygon() const { if(empty_intersection) { return {}; } vector result(dq.size()); for(size_t i = 0; i + 1 < dq.size(); i++) { result[i] = inter(dq[i], dq[i + 1]); } result.back() = inter(dq.back(), dq.front()); return result; } }; ================================================ FILE: geometry/point.hpp ================================================ #ifndef POINT_HPP #define POINT_HPP #include using namespace std; using coord_t = double; struct Point { static constexpr coord_t eps = 1e-9; static inline const coord_t PI = acos((coord_t)-1.0); coord_t x, y; Point(coord_t x = 0, coord_t y = 0) : x(x), y(y) {} Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); } Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); } Point operator*(coord_t c) const { return Point(x * c, y * c); } Point operator/(coord_t c) const { return Point(x / c, y / c); } coord_t operator*(const Point& p) const { return x * p.x + y * p.y; } coord_t operator^(const Point& p) const { return x * p.y - y * p.x; } bool operator==(const Point& p) const { return x == p.x && y == p.y; } bool operator!=(const Point& p) const { return x != p.x || y != p.y; } bool operator<(const Point& p) const { return x != p.x ? x < p.x : y < p.y; } bool operator>(const Point& p) const { return x != p.x ? x > p.x : y > p.y; } bool operator<=(const Point& p) const { return x != p.x ? x < p.x : y <= p.y; } bool operator>=(const Point& p) const { return x != p.x ? x > p.x : y >= p.y; } coord_t norm2() const { return x * x + y * y; } coord_t norm() const { return sqrt(norm2()); } coord_t angle() const { return atan2(y, x); } Point rotate(coord_t a) const { return Point(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a)); } Point perp() const { return Point(-y, x); } Point unit() const { return *this / norm(); } Point normal() const { return perp().unit(); } Point project(const Point& p) const { return *this * (*this * p) / norm2(); } Point reflect(const Point& p) const { return *this * 2 * (*this * p) / norm2() - p; } friend ostream& operator<<(ostream& os, const Point& p) { return os << p.x << ' ' << p.y; } friend istream& operator>>(istream& is, Point& p) { return is >> p.x >> p.y; } friend int ccw(const Point& a, const Point& b, const Point& c) { coord_t v = (b - a) ^ (c - a); if(-eps <= v && v <= eps) { return 0; } else if(v > 0) { return 1; } else { return -1; } } friend bool point_on_segment( const Point& a, const Point& b, const Point& p ) { return ccw(a, b, p) == 0 && p.x >= min(a.x, b.x) - eps && p.x <= max(a.x, b.x) + eps && p.y >= min(a.y, b.y) - eps && p.y <= max(a.y, b.y) + eps; } friend bool point_in_triangle( const Point& a, const Point& b, const Point& c, const Point& p ) { int d1 = ccw(a, b, p); int d2 = ccw(b, c, p); int d3 = ccw(c, a, p); return (d1 >= 0 && d2 >= 0 && d3 >= 0) || (d1 <= 0 && d2 <= 0 && d3 <= 0); } friend Point line_line_intersection( const Point& a1, const Point& b1, const Point& a2, const Point& b2 ) { return a1 + (b1 - a1) * ((a2 - a1) ^ (b2 - a2)) / ((b1 - a1) ^ (b2 - a2)); } friend bool collinear(const Point& a, const Point& b) { return abs(a ^ b) < eps; } friend Point circumcenter(const Point& a, const Point& b, const Point& c) { Point mid_ab = (a + b) / 2.0; Point mid_ac = (a + c) / 2.0; Point perp_ab = (b - a).perp(); Point perp_ac = (c - a).perp(); return line_line_intersection( mid_ab, mid_ab + perp_ab, mid_ac, mid_ac + perp_ac ); } friend coord_t arc_area( const Point& center, coord_t r, const Point& p1, const Point& p2 ) { coord_t theta1 = (p1 - center).angle(); coord_t theta2 = (p2 - center).angle(); if(theta2 < theta1 - eps) { theta2 += 2 * PI; } coord_t d_theta = theta2 - theta1; coord_t cx = center.x, cy = center.y; coord_t area = r * cx * (sin(theta2) - sin(theta1)) - r * cy * (cos(theta2) - cos(theta1)) + r * r * d_theta; return area / 2.0; } friend vector intersect_circles( const Point& c1, coord_t r1, const Point& c2, coord_t r2 ) { Point d = c2 - c1; coord_t dist = d.norm(); if(dist > r1 + r2 + eps || dist < abs(r1 - r2) - eps || dist < eps) { return {}; } coord_t a = (r1 * r1 - r2 * r2 + dist * dist) / (2 * dist); coord_t h_sq = r1 * r1 - a * a; if(h_sq < -eps) { return {}; } if(h_sq < 0) { h_sq = 0; } coord_t h = sqrt(h_sq); Point mid = c1 + d.unit() * a; Point perp_dir = d.perp().unit(); if(h < eps) { return {mid}; } return {mid + perp_dir * h, mid - perp_dir * h}; } friend optional intersect_ray_segment( const Point& ray_start, const Point& ray_through, const Point& seg_a, const Point& seg_b ) { Point ray_dir = ray_through - ray_start; if(ray_dir.norm2() < Point::eps) { return {}; } Point seg_dir = seg_b - seg_a; coord_t denom = ray_dir ^ seg_dir; if(fabs(denom) < eps) { return {}; } coord_t t = ((seg_a - ray_start) ^ seg_dir) / denom; if(t < eps) { return {}; } coord_t s = ((seg_a - ray_start) ^ ray_dir) / denom; if(s < eps || s > 1 - eps) { return {}; } return ray_start + ray_dir * t; } }; #endif // POINT_HPP ================================================ FILE: geometry/polygon.hpp ================================================ #ifndef POLYGON_HPP #define POLYGON_HPP #include #include using namespace std; class Polygon { public: vector points; Polygon() {} Polygon(const vector& points) : points(points) {} int size() const { return points.size(); } const Point& operator[](int i) const { return points[i]; } Point& operator[](int i) { return points[i]; } coord_t area() const { coord_t a = 0; for(int i = 0; i < size(); i++) { a += points[i] ^ points[(i + 1) % size()]; } return a / 2.0; } }; class PointInConvexPolygon { private: Point min_point; vector points_by_angle; void prepare() { points_by_angle = polygon.points; vector::iterator min_point_it = min_element(points_by_angle.begin(), points_by_angle.end()); min_point = *min_point_it; points_by_angle.erase(min_point_it); sort( points_by_angle.begin(), points_by_angle.end(), [&](const Point& a, const Point& b) { int d = ccw(min_point, a, b); if(d != 0) { return d > 0; } return (a - min_point).norm2() < (b - min_point).norm2(); } ); } public: Polygon polygon; PointInConvexPolygon(const Polygon& polygon) : polygon(polygon) { prepare(); } bool contains(const Point& p) const { int l = 0, r = (int)points_by_angle.size() - 1; while(r - l > 1) { int m = (l + r) / 2; if(ccw(min_point, points_by_angle[m], p) >= 0) { l = m; } else { r = m; } } return point_in_triangle( min_point, points_by_angle[l], points_by_angle[r], p ); } }; class ConvexHull : public Polygon { public: int lower_end; vector lower, upper; ConvexHull(const vector& points) { this->points = points; sort(this->points.begin(), this->points.end()); this->points.erase( unique(this->points.begin(), this->points.end()), this->points.end() ); if(this->points.size() <= 2) { lower_end = (int)this->points.size() - 1; lower = this->points; upper = {this->points.back()}; if(this->points.size() > 1) { upper.push_back(this->points.front()); } return; } vector hull = {0}; vector used(this->points.size()); function expand_hull = [&](int i, int min_hull_size) { while((int)hull.size() >= min_hull_size && ccw(this->points[hull[hull.size() - 2]], this->points[hull.back()], this->points[i]) >= 0) { used[hull.back()] = false; hull.pop_back(); } hull.push_back(i); used[i] = true; }; for(int i = 1; i < (int)this->points.size(); i++) { expand_hull(i, 2); } int uhs = hull.size(); for(int i = (int)this->points.size() - 2; i >= 0; i--) { if(!used[i]) { expand_hull(i, uhs + 1); } } hull.pop_back(); vector pts; for(int i: hull) { pts.push_back(this->points[i]); } reverse(pts.begin(), pts.end()); this->points = std::move(pts); lower_end = size() - uhs; lower.assign( this->points.begin(), this->points.begin() + lower_end + 1 ); upper.assign(this->points.begin() + lower_end, this->points.end()); upper.push_back(this->points[0]); } pair tangents_from(const Point& p) const { int n = size(); if(n <= 1) { return {0, 0}; } int a = 0, b = 0; auto update = [&](int id) { id %= n; if(ccw(p, points[a], points[id]) > 0) { a = id; } if(ccw(p, points[b], points[id]) < 0) { b = id; } }; auto bin_search = [&](int low, int high) { if(low >= high) { return; } update(low); int sl = ccw(p, points[low % n], points[(low + 1) % n]); while(low + 1 < high) { int mid = (low + high) / 2; if(ccw(p, points[mid % n], points[(mid + 1) % n]) == sl) { low = mid; } else { high = mid; } } update(high); }; int lid = (int)(lower_bound(lower.begin(), lower.end(), p) - lower.begin()); bin_search(0, lid); bin_search(lid, (int)lower.size() - 1); int uid = (int)(lower_bound(upper.begin(), upper.end(), p, greater()) - upper.begin()); int base = lower_end; bin_search(base, base + uid); bin_search(base + uid, base + (int)upper.size() - 1); return {a, b}; } }; #endif // POLYGON_HPP ================================================ FILE: geometry/voronoi.hpp ================================================ #ifndef VORONOI_HPP #define VORONOI_HPP #include #include using namespace std; // Variation of code by Monogon: https://codeforces.com/blog/entry/85638. // We rotate the points with a small angle as the implementation doesn't // directly handle the case of two equal X coordinates. class VoronoiDiagram { private: static constexpr coord_t INF = 1e100; static inline coord_t sweep_x; struct Arc { mutable Point p, q; mutable int id = 0, i; Arc(const Point& p, const Point& q, int i) : p(p), q(q), i(i) {} coord_t get_y(coord_t x) const { if(q.y == INF) { return INF; } x += Point::eps; Point mid = (p + q) / 2.0; Point dir = (p - mid).perp(); coord_t D = (x - p.x) * (x - q.x); if(D < 0) { return -INF; } if(abs(dir.y) < Point::eps) { return (x < mid.x) ? -INF : INF; } return mid.y + ((mid.x - x) * dir.x + sqrtl(D) * dir.norm()) / dir.y; } bool operator<(const coord_t& y) const { return get_y(sweep_x) < y; } bool operator<(const Arc& o) const { return get_y(sweep_x) < o.get_y(sweep_x); } }; using Beach = multiset>; struct Event { coord_t x; int id; Beach::iterator it; Event(coord_t x, int id, Beach::iterator it) : x(x), id(id), it(it) {} bool operator<(const Event& e) const { return x > e.x; } }; Beach beach_line; vector> vertices; priority_queue event_queue; vector> edges; vector valid; int n, next_vertex_id; void update_vertex_event(Beach::iterator it) { if(it->i == -1) { return; } valid[-it->id] = false; auto prev_it = prev(it); if(collinear(it->q - it->p, prev_it->p - it->p)) { return; } it->id = --next_vertex_id; valid.push_back(true); Point center = circumcenter(it->p, it->q, prev_it->p); coord_t event_x = center.x + (center - it->p).norm(); bool valid_event = event_x > sweep_x - Point::eps && prev_it->get_y(event_x) + Point::eps > it->get_y(event_x); if(valid_event) { event_queue.push(Event(event_x, it->id, it)); } } void add_edge(int i, int j) { if(i == -1 || j == -1) { return; } edges.push_back({vertices[i].second, vertices[j].second}); } void add_point(int i) { Point p = vertices[i].first; auto split_it = beach_line.lower_bound(p.y); auto new_it = beach_line.insert(split_it, Arc(p, split_it->p, i)); auto prev_it = beach_line.insert(new_it, Arc(split_it->p, p, split_it->i)); add_edge(i, split_it->i); update_vertex_event(prev_it); update_vertex_event(new_it); update_vertex_event(split_it); } void remove_arc(Beach::iterator it) { auto prev_it = prev(it); auto next_it = next(it); beach_line.erase(it); prev_it->q = next_it->p; add_edge(prev_it->i, next_it->i); update_vertex_event(prev_it); update_vertex_event(next_it); } public: VoronoiDiagram(const vector& points, bool fix_coordinates = true) { n = points.size(); vertices.resize(n); for(int i = 0; i < n; i++) { vertices[i] = {points[i], i}; } if(fix_coordinates && n > 0) { // Rotate around center by 1.0 radians. for(int i = 0; i < n; i++) { vertices[i].first = vertices[i].first.rotate(1.0); } } sort(vertices.begin(), vertices.end()); } vector> compute(coord_t X = 1e9) { edges.clear(); beach_line.clear(); event_queue = priority_queue(); X *= 3; beach_line.insert(Arc(Point(-X, -X), Point(-X, X), -1)); beach_line.insert(Arc(Point(-X, X), Point(INF, INF), -1)); for(int i = 0; i < n; i++) { event_queue.push(Event(vertices[i].first.x, i, beach_line.end())); } next_vertex_id = 0; valid.assign(1, false); while(!event_queue.empty()) { Event e = event_queue.top(); event_queue.pop(); sweep_x = e.x; if(e.id >= 0) { add_point(e.id); } else if(valid[-e.id]) { remove_arc(e.it); } } return edges; } const vector>& get_edges() const { return edges; } }; #endif // VORONOI_HPP ================================================ FILE: graph/bcc.hpp ================================================ #include using namespace std; class biconnected_components { private: vector low, disc; void tarjan(int u, int pr, int &dfs_time, vector> &st) { low[u] = disc[u] = ++dfs_time; int child_cnt = 0; for(int v: adj[u]) { if(v != pr) { if(disc[v] == -1) { st.push_back({u, v}); tarjan(v, u, dfs_time, st); child_cnt++; low[u] = min(low[u], low[v]); if((pr == -1 && child_cnt > 1) || (pr != -1 && disc[u] <= low[v])) { vector> curr = {make_pair(u, v)}; while(st.back() != make_pair(u, v)) { curr.push_back(st.back()); st.pop_back(); } st.pop_back(); if(curr.size() == 1) { bridges.push_back(curr.back()); } else { bcc.push_back(curr); } } } else if(disc[v] < disc[u]) { low[u] = min(low[u], disc[v]); st.push_back({u, v}); } } } } public: int n; vector> adj; vector>> bcc; vector> bridges; void add_edge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void init(int _n) { n = _n; adj.assign(n + 1, {}); } void compute_bcc() { bcc.clear(); bridges.clear(); low.assign(n + 1, -1); disc.assign(n + 1, -1); int dfs_time = 0; for(int i = 0; i < n; i++) { if(disc[i] == -1) { vector> st; tarjan(i, -1, dfs_time, st); if(!st.empty()) { if(st.size() == 1) { bridges.push_back(st.back()); } else { bcc.push_back(st); } st.clear(); } } } } }; // int n, m; // biconnected_components bcc; // void read() { // cin >> n >> m; // bcc.init(n); // for(int i = 0; i < m; i++) { // int u, v; // cin >> u >> v; // bcc.add_edge(u, v); // } // } ================================================ FILE: graph/bipartite_coloring.hpp ================================================ #include #include using namespace std; struct Edge { int u, v, idx; Edge(int _u = 0, int _v = 0, int _idx = 0) : u(_u), v(_v), idx(_idx) {} }; class BipartiteColoring { private: vector>> edges_for_ver; vector used; vector>> adj; vector memory_m; template static void make_larger_if_needed(vector& v, int size) { if(v.size() < size) { v.resize(size); } } pair, vector> partition_edges_euler( const vector& edges, const vector& vers, int n ) { make_larger_if_needed(adj, 2 * n); make_larger_if_needed(memory_m, edges.size()); for(int v: vers) { adj[v].clear(); adj[v + n].clear(); } for(int ei = 0; ei < (int)edges.size(); ei++) { auto e = edges[ei]; adj[e.u].push_back({e.v + n, ei}); adj[e.v + n].push_back({e.u, ei}); memory_m[ei] = 0; } function&, vector&)> dfs = [&](int v, vector& subgraph_0, vector& subgraph_1) { while(!adj[v].empty()) { auto [u, ei] = adj[v].back(); adj[v].pop_back(); if(memory_m[ei] == 1) { continue; } memory_m[ei] = 1; dfs(u, subgraph_0, subgraph_1); if(v < n) { subgraph_0.push_back(edges[ei]); } else { subgraph_1.push_back(edges[ei]); } break; } }; vector subgraph_0, subgraph_1; for(int v: vers) { while(!adj[v].empty()) { dfs(v, subgraph_0, subgraph_1); } } return {subgraph_0, subgraph_1}; } vector hopcroft_one_colour( const vector& edges, int n, vector>& answer ) { make_larger_if_needed(edges_for_ver, n); make_larger_if_needed(used, (int)edges.size()); for(int i = 0; i < n; i++) { edges_for_ver[i].clear(); } for(int i = 0; i < (int)edges.size(); i++) { used[i] = false; } HopcroftKarp bm(n, n); for(int i = 0; i < (int)edges.size(); i++) { auto e = edges[i]; bm.add_edge(e.u, e.v); edges_for_ver[e.u].push_back({e, i}); } int max_match = bm.max_matching(); assert(max_match == n); vector assigned; vector> matches = bm.get_matching(); for(auto [u, v]: matches) { for(auto [e, ei]: edges_for_ver[u]) { if(e.v == v && !used[ei]) { used[ei] = true; assigned.push_back(e); break; } } } vector new_edges; for(int i = 0; i < (int)edges.size(); i++) { if(!used[i]) { new_edges.push_back(edges[i]); } } answer.push_back(assigned); return new_edges; } // We don't actually use this function as it's actually slower than the // above one. vector good_worst_case_one_colour( const vector& _edges, int n, int original_m, vector>& answer ) { static vector memory_m; make_larger_if_needed(memory_m, original_m); int m = _edges.size(); int d = m / n; int l = 0; while((1 << l) <= m) { l++; } int alpha = (1 << l) / d; int beta = (1 << l) - d * alpha; vector edges = _edges; vector multiplicity(edges.size(), alpha); for(int i = 0; i < m; i++) { auto& e = edges[i]; memory_m[e.idx] = i; } for(int i = 0; i < n; i++) { edges.push_back(Edge(i, i, -1)); multiplicity.push_back(beta); } vector vers(n); iota(vers.begin(), vers.end(), 0); while(l--) { vector new_edges; for(int i = 0; i < (int)edges.size(); i++) { if(multiplicity[i] % 2) { new_edges.push_back(edges[i]); } multiplicity[i] /= 2; } auto [subgraph_0, subgraph_1] = partition_edges_euler(new_edges, vers, n); int cnt0 = 0, cnt1 = 0; for(auto& e: subgraph_0) { if(e.idx == -1) { cnt0++; } } for(auto& e: subgraph_1) { if(e.idx == -1) { cnt1++; } } if(cnt0 > cnt1) { swap(subgraph_0, subgraph_1); } for(int i = 0; i < (int)subgraph_0.size(); i++) { auto& e = subgraph_0[i]; if(e.idx == -1) { multiplicity[m + e.u] += 1; } else { int multiplicity_idx = memory_m[e.idx]; multiplicity[multiplicity_idx] += 1; } } } vector answer_edges, subgraph_rest; for(int i = 0; i < m; i++) { auto& e = edges[i]; if(multiplicity[i]) { answer_edges.push_back(e); } else { subgraph_rest.push_back(e); } } answer.push_back(answer_edges); return subgraph_rest; } public: int euler_colour( const vector& edges, int n, int m, vector>& answer ) { static vector memory; make_larger_if_needed(memory, n); vector vers, _vers; for(auto e: edges) { _vers.push_back(e.u); _vers.push_back(e.v); } int max_degree = 0; for(int v: _vers) { memory[v] = -1; } for(int v: _vers) { if(memory[v] == -1) { vers.push_back(v); memory[v] = 0; } } for(auto e: edges) { memory[e.u]++; max_degree = max(max_degree, memory[e.u]); } if(max_degree == 0) { return 0; } if(max_degree == 1) { answer.push_back({}); for(auto e: edges) { answer.back().push_back(e); } return 1; } if(max_degree % 2 == 1) { auto subgraph = hopcroft_one_colour(edges, n, answer); // Uncomment if we want something that is good in worst case. // auto subgraph = good_worst_case_one_colour(edges, n, m, answer); return 1 + euler_colour(subgraph, n, m, answer); } auto [subgraph_0, subgraph_1] = partition_edges_euler(edges, vers, n); int colour_num_subgraph_0 = euler_colour(subgraph_0, n, m, answer); int d = max_degree, q = 0; while((1 << q) < (max_degree / 2)) { q++; } int to_remove_count = (1 << q) - (max_degree / 2); if(to_remove_count > 0 && colour_num_subgraph_0 >= to_remove_count) { for(int i = answer.size() - 1; i >= answer.size() - to_remove_count; i--) { for(auto& e: answer[i]) { subgraph_1.push_back(e); } } answer.erase(answer.end() - to_remove_count, answer.end()); } int colour_num_subgraph_1 = euler_colour(subgraph_1, n, m, answer); return colour_num_subgraph_0 + colour_num_subgraph_1; } }; ================================================ FILE: graph/bipartite_matching.hpp ================================================ #include using namespace std; class BipartiteMatching { private: int n, m, visited_timer; vector visited; bool try_kuhn(int u) { if(visited[u] == visited_timer) { return false; } visited[u] = visited_timer; for(int v: adj[u]) { if(match[v] == -1 || try_kuhn(match[v])) { match[v] = u; inv_match[u] = v; return true; } } return false; } int pre_match() { int matching_size = 0; for(int u = 0; u < n; u++) { if(inv_match[u] == -1) { for(int v: adj[u]) { if(match[v] == -1) { matching_size++; match[v] = u; inv_match[u] = v; break; } } } } return matching_size; } public: vector match, inv_match; vector> adj; BipartiteMatching(int _n, int _m = -1) : n(_n), m(_m == -1 ? _n : _m) { adj.assign(n, vector()); clear(false); } void clear(bool clear_adj = true) { match.assign(m, -1); inv_match.assign(n, -1); visited_timer = 0; visited.assign(n, 0); if(clear_adj) { adj.assign(n, vector()); } } void add_edge(int u, int v) { adj[u].push_back(v); } bool match_vertex(int u) { if(inv_match[u] != -1) { return false; } visited_timer++; return try_kuhn(u); } int max_matching(bool shuffle_edges = false, bool pre_matching = false) { if(shuffle_edges) { for(int i = 0; i < n; i++) { shuffle( adj[i].begin(), adj[i].end(), mt19937( chrono::steady_clock::now().time_since_epoch().count() ) ); } } int ans = 0; if(pre_matching) { ans += pre_match(); } for(int i = 0; i < n; i++) { ans += match_vertex(i); } return ans; } vector> get_matching() { vector> res; for(int i = 0; i < m; i++) { if(match[i] != -1) { res.emplace_back(match[i], i); } } return res; } }; ================================================ FILE: graph/dijkstra_vlog.hpp ================================================ #include #include using namespace std; template vector dijkstra(int src, const vector>>& adj) { static auto cmp_min = [](int a, int b) -> bool { return a > b; }; int n = adj.size(); vector dist(n, numeric_limits::max()); vector pq_node(n, -1); vector pq_node_to_ver(n, -1); Heap pq; function update = [&](int u, T d) { dist[u] = min(dist[u], d); if(pq_node[u] == -1) { pq_node[u] = pq.push(dist[u]); pq_node_to_ver[pq_node[u]] = u; } else { pq.update(pq_node[u], dist[u]); } }; update(src, 0); while(!pq.empty()) { int u = pq_node_to_ver[pq.top_node()]; pq.pop(); for(auto [v, w]: adj[u]) { update(v, dist[u] + w); } } return dist; } ================================================ FILE: graph/directed_cactus.hpp ================================================ #include using namespace std; class DirectedCactus { private: int n; vector> adj; vector nxt, jump, dep, in_time, out_time; void dfs(int u, int &dfs_time, vector &used, vector &buff) { used[u] = true; in_time[u] = dfs_time++; buff.push_back(u); for(int v: adj[u]) { if(!used[v]) { dep[v] = dep[u] + 1; dfs(v, dfs_time, used, buff); } } out_time[u] = dfs_time - 1; } public: DirectedCactus() { n = 0; nxt.clear(); } DirectedCactus(vector _nxt) { init(_nxt); } void init(vector _nxt) { nxt = _nxt; n = nxt.size(); in_time.resize(n); out_time.resize(n); jump.resize(n); adj.assign(n, {}); for(int i = 0; i < n; i++) { adj[nxt[i]].push_back(i); } int dfs_time = 0; vector used(n, false); dep.assign(n, 0); for(int i = 0; i < n; i++) { if(!used[i]) { vector buff; int root = i; while(!used[root]) { used[root] = true; buff.push_back(root); root = nxt[root]; } for(int u: buff) { used[u] = false; } buff.clear(); dfs(root, dfs_time, used, buff); for(int u: buff) { jump[u] = nxt[root]; } } } } int distance(int from, int to) { if(in_time[to] <= in_time[from] && out_time[from] <= out_time[to]) { return dep[from] - dep[to]; } int to_add = dep[from] + 1; from = jump[from]; if(in_time[to] <= in_time[from] && out_time[from] <= out_time[to]) { return dep[from] - dep[to] + to_add; } return -1; } }; ================================================ FILE: graph/dsu.hpp ================================================ #include using namespace std; class DSU { public: int n; vector par; vector sz; DSU(int _n = 0) { init(_n); } void init(int _n) { n = _n; par.assign(n + 1, 0); sz.assign(n + 1, 0); for(int i = 0; i <= n; i++) { par[i] = i; sz[i] = 1; } } int root(int u) { return par[u] = ((u == par[u]) ? u : root(par[u])); } bool connected(int x, int y) { return root(x) == root(y); } int unite(int x, int y) { x = root(x), y = root(y); if(x == y) { return x; } if(sz[x] > sz[y]) { swap(x, y); } par[x] = y; sz[y] += sz[x]; return y; } vector> components() { vector> comp(n + 1); for(int i = 0; i <= n; i++) { comp[root(i)].push_back(i); } return comp; } }; ================================================ FILE: graph/eppstein_shortest_paths.hpp ================================================ #include #include using namespace std; template class EppsteinShortestPaths { private: const T inf = numeric_limits::max() / 2; struct Edge { int u, v; T w; Edge(int _u = 0, int _v = 0, T _w = 0) : u(_u), v(_v), w(_w) {} }; pair, vector> build_dijkstra_tree(int t) { vector dist(n, inf); priority_queue, vector>, greater<>> pq; dist[t] = 0; pq.emplace(0, t); while(!pq.empty()) { auto [d, u] = pq.top(); pq.pop(); if(d != dist[u]) { continue; } for(auto [v, idx]: rev_adj[u]) { T nd = d + edges[idx].w; if(nd < dist[v]) { dist[v] = nd; pq.emplace(nd, v); } } } vector tree(n, -1); for(int u = 0; u < n; u++) { for(auto [v, idx]: adj[u]) { if(dist[u] == dist[v] + edges[idx].w) { tree[u] = idx; break; } } } return {dist, tree}; } vector topsort(const vector& tree) { vector deg(n, 0); for(int u = 0; u < n; u++) { if(tree[u] != -1) { deg[edges[tree[u]].v]++; } } queue q; for(int u = 0; u < n; u++) { if(deg[u] == 0) { q.push(u); } } vector order; while(!q.empty()) { int u = q.front(); q.pop(); order.push_back(u); if(tree[u] != -1) { int v = edges[tree[u]].v; deg[v]--; if(deg[v] == 0) { q.push(v); } } } return order; } public: int n; vector>> adj; vector>> rev_adj; vector edges; void init(int _n) { n = _n; edges.clear(); adj.assign(n, {}); rev_adj.assign(n, {}); } EppsteinShortestPaths(int n = 0) { init(n); } int add_edge(int u, int v, T w, bool directed = true) { int idx = edges.size(); edges.emplace_back(u, v, w); adj[u].emplace_back(v, idx); rev_adj[v].emplace_back(u, idx); if(!directed) { edges.emplace_back(v, u, w); adj[v].emplace_back(u, idx + 1); rev_adj[u].emplace_back(v, idx + 1); } return idx; } vector get_k_shortest_paths(int s, int t, int k) { auto dist_and_tree = build_dijkstra_tree(t); auto dist = dist_and_tree.first; auto tree = dist_and_tree.second; if(dist[s] == inf || k <= 0) { return vector(); } vector>> heaps(n); for(int u = 0; u < n; u++) { for(auto& [v, idx]: adj[u]) { if(tree[u] == idx) { continue; } T cost = edges[idx].w + dist[v] - dist[u]; heaps[u].push({cost, v}); } } auto order = topsort(tree); reverse(order.begin(), order.end()); for(int u: order) { if(tree[u] != -1) { int par = edges[tree[u]].v ^ edges[tree[u]].u ^ u; heaps[u] = heaps[u].merge(heaps[par]); } } vector ans = {dist[s]}; if(heaps[s].empty()) { return ans; } priority_queue< pair>>, vector>>>, greater<>> pq; pq.emplace(dist[s] + heaps[s].top().first, heaps[s].copy()); while(!pq.empty() && (int)ans.size() < k) { auto [d, meld_heap] = pq.top(); pq.pop(); ans.push_back(d); auto [head, left_heap, right_heap] = meld_heap.trio(); if(!left_heap.empty()) { pq.emplace(d - head.first + left_heap.top().first, left_heap); } if(!right_heap.empty()) { pq.emplace(d - head.first + right_heap.top().first, right_heap); } int v = head.second; if(!heaps[v].empty()) { pq.emplace(d + heaps[v].top().first, heaps[v].copy()); } } return ans; } }; ================================================ FILE: graph/eulerian_paths.hpp ================================================ #include using namespace std; // This implementation find cnt_odd_vertices / 2 eulerian paths that cover // all edges of the graph. The way to use it is to create an object and // incrementally add edges to it. Then, call find_paths() to get the paths. // If the number of paths is 1, we have either a cycle or a path. // // Tested on: // https://codeforces.com/problemsets/acmsguru/problem/99999/101 // https://codesprintla24.kattis.com/contests/codesprintla24open/problems/catbusplan class EulerianPaths { private: void dfs(int u, vector& path, vector& used, vector& po) { for(; po[u] < (int)adj[u].size();) { int idx = po[u]++; if(!used[adj[u][idx].second >> 1]) { used[adj[u][idx].second >> 1] = true; dfs(adj[u][idx].first, path, used, po); path.push_back(adj[u][idx].second); } } } public: int n, m; vector deg; vector>> adj; vector> edges; EulerianPaths(int _n = 0) { init(_n); } void init(int _n) { n = _n; m = 0; adj.assign(n + 1, {}); deg.assign(n + 1, 0); edges.clear(); } int add_edge(int u, int v) { adj[u].push_back({v, m * 2}); adj[v].push_back({u, m * 2 + 1}); edges.push_back({u, v}); deg[u]++; deg[v]++; m++; return edges.size() - 1; } vector> find_paths() { vector used(m, false); vector po(n + 1, 0); vector odd_vertices; for(int i = 0; i <= n; i++) { if(deg[i] % 2 == 1) { odd_vertices.push_back(i); } } int total_edges = m; for(int i = 0; i < (int)odd_vertices.size() / 2; i++) { int u = odd_vertices[2 * i], v = odd_vertices[2 * i + 1]; adj[u].push_back({v, 2 * total_edges}); adj[v].push_back({u, 2 * total_edges + 1}); total_edges++; used.push_back(false); edges.push_back({u, v}); } vector> paths; for(int u = 0; u <= n; u++) { if(!adj[u].empty()) { vector path; dfs(u, path, used, po); if(!path.empty()) { // Rotate the path so that we always start with a fake edge // if there is at least one. auto it = find_if(path.begin(), path.end(), [&](int x) { return x >= 2 * m; }); if(it != path.end()) { rotate(path.begin(), it, path.end()); } vector current_path; for(int x: path) { if(x < 2 * m) { current_path.push_back(x); } else if(!current_path.empty()) { paths.push_back(current_path); current_path.clear(); } } if(!current_path.empty()) { paths.push_back(current_path); } } } } return paths; } pair get_edge(int edge_i) { if(edge_i & 1) { return edges[edge_i >> 1]; } else { return {edges[edge_i >> 1].second, edges[edge_i >> 1].first}; } } vector> get_path_edges(const vector& path) { vector> result; for(int edge_i: path) { result.push_back(get_edge(edge_i)); } return result; } bool is_cycle(const vector& path) { int start = get_edge(path[0]).first; int end = get_edge(path.back()).second; return start == end; } }; ================================================ FILE: graph/graph.hpp ================================================ #include #include using namespace std; class UndirectedGraph { public: int n, m; vector> adj; vector> edges; bool maintain_dsu; DSU dsu; UndirectedGraph(int _n = 0, bool _maintain_dsu = false) { init(_n, _maintain_dsu); } void init(int _n, bool _maintain_dsu = false) { m = 0; n = _n; maintain_dsu = _maintain_dsu; adj.assign(n + 1, {}); edges.clear(); if(maintain_dsu) { dsu.init(n); } } void read_edges(int _m, int idx_offset = -1) { for(int i = 0; i < _m; i++) { int u, v; cin >> u >> v; u += idx_offset; v += idx_offset; add_edge(u, v); } } void add_edges(const vector>& new_edges) { for(auto [u, v]: new_edges) { add_edge(u, v); } } void add_edge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); edges.emplace_back(u, v); m++; if(maintain_dsu) { dsu.unite(u, v); } } DSU& get_dsu() { if(!maintain_dsu) { dsu.init(n); for(auto [u, v]: edges) { dsu.unite(u, v); } } return dsu; } }; ================================================ FILE: graph/hopcroft_karp.hpp ================================================ #include using namespace std; // Hopcroft-Karp algorithm for bipartite matching that runs in O(E sqrt(V)). // Motivated by this submission: https://judge.yosupo.jp/submission/52112, but // adapted to match coding_library/graph/bipartite_matching.cpp. class HopcroftKarp { private: int n, m; vector dist; bool bfs() { queue q; dist.assign(n, -1); for(int u = 0; u < n; u++) { if(inv_match[u] == -1) { dist[u] = 0; q.push(u); } } bool found = false; while(!q.empty()) { int u = q.front(); q.pop(); for(int v: adj[u]) { int m = match[v]; if(m == -1) { found = true; } else if(dist[m] == -1) { dist[m] = dist[u] + 1; q.push(m); } } } return found; } bool dfs(int u) { for(int v: adj[u]) { int m = match[v]; if(m == -1 || (dist[m] == dist[u] + 1 && dfs(m))) { inv_match[u] = v; match[v] = u; return true; } } dist[u] = -1; return false; } public: vector match, inv_match; vector> adj; HopcroftKarp(int _n, int _m = -1) : n(_n), m(_m == -1 ? _n : _m) { adj.assign(n, vector()); clear(false); } void clear(bool clear_adj = true) { match.assign(m, -1); inv_match.assign(n, -1); if(clear_adj) { adj.assign(n, vector()); } } void add_edge(int u, int v) { adj[u].push_back(v); } int max_matching(bool shuffle_edges = false) { if(shuffle_edges) { for(int i = 0; i < n; i++) { shuffle( adj[i].begin(), adj[i].end(), mt19937( chrono::steady_clock::now().time_since_epoch().count() ) ); } } int ans = 0; while(bfs()) { for(int u = 0; u < n; u++) { if(inv_match[u] == -1 && dfs(u)) { ans++; } } } return ans; } vector> get_matching() { vector> matches; for(int u = 0; u < n; u++) { if(inv_match[u] != -1) { matches.emplace_back(u, inv_match[u]); } } return matches; } pair, vector> minimum_vertex_cover() { vector left_cover, right_cover; bfs(); for(int u = 0; u < n; u++) { if(dist[u] == -1) { left_cover.push_back(u); } } for(int v = 0; v < m; v++) { if(match[v] != -1 && dist[match[v]] != -1) { right_cover.push_back(v); } } return {left_cover, right_cover}; } }; using BipartiteMatching = HopcroftKarp; ================================================ FILE: graph/hungarian_algorithm.hpp ================================================ #include using namespace std; // Based on http://e-maxx.ru/algo/assignment_hungary#6 but wrapped in a class // and zero-based indexing. Optimizes the assignment so that the cost is // minimized. Also make sure that n <= m. template class HungarianAlgorithm { private: const T INF = numeric_limits::max() / 2; vector way; public: int n, m; vector> cost; vector assignment; vector pot_left, pot_right; HungarianAlgorithm(const vector>& a) { n = a.size(); m = a[0].size(); assert(n <= m); cost.assign(n + 1, vector(m + 1)); for(int i = 0; i < n; i++) { for(int j = 0; j < m; j++) { cost[i][j] = a[i][j]; } } pot_left.assign(n + 1, 0); pot_right.assign(m + 1, 0); assignment.assign(m + 1, n); way.assign(m + 1, m); for(int i = 0; i < n; i++) { assignment[m] = i; int j0 = m; vector minv(m + 1, INF); vector used(m + 1, false); do { used[j0] = true; int i0 = assignment[j0], j1 = m; T delta = INF; for(int j = 0; j < m; j++) { if(!used[j]) { T cur = cost[i0][j] - pot_left[i0] - pot_right[j]; if(cur < minv[j]) { minv[j] = cur; way[j] = j0; } if(minv[j] < delta) { delta = minv[j]; j1 = j; } } } for(int j = 0; j <= m; j++) { if(used[j]) { pot_left[assignment[j]] += delta; pot_right[j] -= delta; } else { minv[j] -= delta; } } j0 = j1; } while(assignment[j0] != n); do { int j1 = way[j0]; assignment[j0] = assignment[j1]; j0 = j1; } while(j0 != m); } } T get_cost() { T ans = 0; for(int j = 0; j < m; j++) { ans += cost[assignment[j]][j]; } return ans; } }; ================================================ FILE: graph/maxflow.hpp ================================================ #include using namespace std; template class MaxFlow { private: struct Edge { T flow, cap; int idx, rev, to; Edge(int _to, int _rev, T _flow, T _cap, int _idx) : to(_to), rev(_rev), flow(_flow), cap(_cap), idx(_idx) {} }; vector dist, po; int n; bool bfs(int s, int t) { fill(dist.begin(), dist.end(), -1); fill(po.begin(), po.end(), 0); queue q; q.push(s); dist[s] = 0; while(!q.empty()) { int u = q.front(); q.pop(); for(Edge e: adj[u]) { if(dist[e.to] == -1 && e.flow < e.cap) { dist[e.to] = dist[u] + 1; q.push(e.to); } } } return dist[t] != -1; } T dfs(int u, int t, T fl = inf) { if(u == t) { return fl; } for(; po[u] < (int)adj[u].size(); po[u]++) { auto& e = adj[u][po[u]]; if(dist[e.to] == dist[u] + 1 && e.flow < e.cap) { T f = dfs(e.to, t, min(fl, e.cap - e.flow)); e.flow += f; adj[e.to][e.rev].flow -= f; if(f > 0) { return f; } } } return 0; } public: constexpr static T inf = numeric_limits::max(); MaxFlow(int n = 0) { init(n); } vector> adj; void init(int _n) { n = _n; adj.assign(n + 1, {}); dist.resize(n + 1); po.resize(n + 1); } void add_edge(int u, int v, T w, int idx = -1) { adj[u].push_back(Edge(v, adj[v].size(), 0, w, idx)); adj[v].push_back(Edge(u, adj[u].size() - 1, 0, 0, -1)); } T flow(int s, int t) { assert(s != t); T ret = 0, to_add; while(bfs(s, t)) { while((to_add = dfs(s, t))) { ret += to_add; } } return ret; } }; ================================================ FILE: graph/mincost_circulation.hpp ================================================ #include using namespace std; // In some rare cases, we might want to find the min cost circulation instead of // min cost flow, and this is non-trivial in the presence of negative cycles (as // we would like to select them up to their capacity). The two common approaches are // using cost scaling push relabel, or the network simplex. Some resources to check are: // // - https://codeforces.com/blog/entry/104075?#comment-925064 // - https://codeforces.com/blog/entry/57018 // - https://codeforces.com/blog/entry/94190 (+ regular simplex) // // Here we use bicsi's implementation, based on brunovsky's blog (last one mentioned), which // is fairly clean and works well (and it's easy to recover the answer). template class MinCostCirculation { private: struct Edge { int from, to; T capacity, cost, flow; Edge(int _from, int _to, T _capacity, T _cost, T _flow = 0) : from(_from), to(_to), capacity(_capacity), cost(_cost), flow(_flow) {} }; int n; vector edges; vector pei, depth; vector dual; vector> tree; void dfs(int node) { for(auto ei: tree[node]) { if(ei == pei[node]) { continue; } int vec = edges[ei].to; dual[vec] = dual[node] + edges[ei].cost; pei[vec] = (ei ^ 1); depth[vec] = 1 + depth[node]; dfs(vec); } } template void walk(int ei, CB&& cb) { cb(ei); int a = edges[ei].from, b = edges[ei].to; while(a != b) { if(depth[a] > depth[b]) { cb(pei[a] ^ 1), a = edges[pei[a]].to; } else { cb(pei[b]), b = edges[pei[b]].to; } } } public: MinCostCirculation(int _n = 0) { init(_n); } void init(int _n) { n = _n; edges.clear(); pei.assign(n + 1, -1); depth.assign(n + 1, 0); dual.assign(n + 1, 0); tree.assign(n + 1, set()); } int size() const { return n; } int add_edge(int from, int to, T capacity, T cost) { int id = edges.size(); edges.push_back(Edge(from, to, capacity, cost, 0)); edges.push_back(Edge(to, from, 0, -cost, 0)); return id; } T min_circulation() { for(int i = 0; i < n; i++) { int ei = add_edge(n, i, 0, 0); tree[n].insert(ei); tree[i].insert(ei ^ 1); } T answer = 0; T flow; int cost, ein, eout, ptr = 0; const int B = 3 * n; for(int z = 0; z < (int)edges.size() / B + 1; z++) { if(!z) { dfs(n); } pair pin = {0, -1}; for(int t = 0; t < B; t++, (++ptr) %= (int)edges.size()) { auto& e = edges[ptr]; if(e.flow < e.capacity) { pin = min(pin, make_pair(dual[e.from] + e.cost - dual[e.to], ptr)); } } tie(cost, ein) = pin; if(cost == 0) { continue; } pair pout = {edges[ein].capacity - edges[ein].flow, ein}; walk(ein, [&](int ei) { pout = min(pout, make_pair(edges[ei].capacity - edges[ei].flow, ei)); }); tie(flow, eout) = pout; walk(ein, [&](int ei) { edges[ei].flow += flow, edges[ei ^ 1].flow -= flow; }); tree[edges[ein].from].insert(ein); tree[edges[ein].to].insert(ein ^ 1); tree[edges[eout].from].erase(eout); tree[edges[eout].to].erase(eout ^ 1); answer += flow * cost; z = -1; } return answer; } const Edge& get_edge(int id) const { return edges[id]; } }; ================================================ FILE: graph/mincost_flow.hpp ================================================ #include using namespace std; // Based on Ormlis' implementation template class MinCostFlow { private: const static T inf = numeric_limits::max(); struct Edge { int to, rev; T capacity, cost, flow; Edge(int _to, int _rev, T _capacity, T _cost, T _flow) : to(_to), rev(_rev), capacity(_capacity), cost(_cost), flow(_flow) {} }; int n; vector> g; vector potential; vector> parent; vector> dist; void build_potential(int source) { fill(potential.begin(), potential.end(), inf); potential[source] = 0; while(true) { bool any = false; for(int v = 0; v < n; v++) { for(const auto& e: g[v]) { if(e.capacity != 0 && potential[v] != inf && potential[v] + e.cost < potential[e.to]) { potential[e.to] = potential[v] + e.cost; any = true; } } } if(!any) { break; } } } bool dijkstra(int source, int sink, T flow_limit, T flow) { fill(dist.begin(), dist.end(), make_pair(inf, flow_limit - flow)); dist[source].first = 0; priority_queue, vector>, greater<>> q; q.push({0, source}); while(!q.empty()) { auto [cur_dist, v] = q.top(); q.pop(); if(cur_dist > dist[v].first) { continue; } for(const auto& e: g[v]) { if(potential[e.to] != inf && cur_dist + e.cost - potential[e.to] + potential[v] < dist[e.to].first && e.flow < e.capacity) { parent[e.to] = {v, e.rev}; dist[e.to] = { cur_dist + e.cost - potential[e.to] + potential[v], min(dist[v].second, e.capacity - e.flow) }; q.push({dist[e.to].first, e.to}); } } } return dist[sink].first != inf; } public: MinCostFlow(int _n = 0) { init(_n); } void init(int _n) { n = _n; g.assign(n, {}); potential.resize(n); parent.resize(n); dist.resize(n); } int size() const { return n; } int add_edge(int from, int to, T capacity, T cost) { int id = g[from].size(); g[from].push_back( Edge(to, g[to].size() + (from == to), capacity, cost, 0) ); g[to].push_back(Edge(from, id, 0, -cost, 0)); return id; } pair flow(int source, int sink, T flow_limit = inf) { for(int v = 0; v < n; v++) { for(auto& e: g[v]) { e.flow = 0; } } T cost = 0, flow = 0; build_potential(source); while(flow < flow_limit && dijkstra(source, sink, flow_limit, flow)) { T delta = dist[sink].second; flow += delta; for(int v = sink; v != source; v = parent[v].first) { auto& e = g[parent[v].first][g[v][parent[v].second].rev]; cost += e.cost * delta; e.flow += delta; g[v][parent[v].second].flow -= delta; } for(int i = 0; i < n; i++) { if(dist[i].first != inf) { potential[i] += dist[i].first; } } } return {cost, flow}; } }; ================================================ FILE: graph/scc.hpp ================================================ #include using namespace std; class StronglyConnectedComponents { private: vector visited; void dfs1(int u) { visited[u] = true; for(int v: adj[u]) { if(!visited[v]) { dfs1(v); } } top_sort.push_back(u); } void dfs2(int u) { for(int v: radj[u]) { if(comp[v] == -1) { comp[v] = comp[u]; dfs2(v); } } } public: int n; vector> adj, radj; vector comp, comp_ids, top_sort; StronglyConnectedComponents() {} StronglyConnectedComponents(int _n) { init(_n); } void add_edge(int u, int v) { adj[u].push_back(v); radj[v].push_back(u); } void init(int _n) { n = _n; comp_ids.clear(); top_sort.clear(); adj.assign(n, {}); radj.assign(n, {}); } void find_components() { comp.assign(n, -1); visited.assign(n, false); for(int i = 0; i < n; i++) { if(!visited[i]) { dfs1(i); } } reverse(top_sort.begin(), top_sort.end()); for(int u: top_sort) { if(comp[u] == -1) { comp[u] = (int)comp_ids.size(); comp_ids.push_back(comp[u]); dfs2(u); } } } }; ================================================ FILE: graph/st_numbering.hpp ================================================ #include using namespace std; class STNumbering { private: vector low, disc, par, sign; vector preorder; int dfs_time; bool tarjan_check(int u, int pr) { low[u] = disc[u] = ++dfs_time; int child_cnt = 0; for(int v: adj[u]) { if(v != pr) { if(disc[v] == -1) { child_cnt++; if(!tarjan_check(v, u)) { return false; } low[u] = min(low[u], low[v]); if(pr != -1 && low[v] >= disc[u]) { return false; } } else { low[u] = min(low[u], disc[v]); } } } if(pr == -1 && child_cnt > 1) { return false; } return true; } void tarjan(int u, int pr) { low[u] = disc[u] = ++dfs_time; for(int v: adj[u]) { if(v != pr) { if(disc[v] == -1) { preorder.push_back(v); tarjan(v, u); low[u] = min(low[u], low[v]); par[v] = u; } else { low[u] = min(low[u], disc[v]); } } } } public: int n; vector> adj; vector ordering; STNumbering() {} STNumbering(int _n) { init(_n); } void init(int _n) { n = _n; adj.assign(n, {}); ordering.clear(); } void add_edge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } bool find_ordering(int s, int t) { low.assign(n, -1); disc.assign(n, -1); par.assign(n, -1); sign.assign(n, 0); preorder.clear(); ordering.clear(); dfs_time = 0; adj[s].push_back(t); adj[t].push_back(s); if(!tarjan_check(t, -1)) { adj[s].pop_back(); adj[t].pop_back(); return false; } for(int i = 0; i < n; i++) { if(disc[i] == -1) { adj[s].pop_back(); adj[t].pop_back(); return false; } } fill(low.begin(), low.end(), -1); fill(disc.begin(), disc.end(), -1); fill(sign.begin(), sign.end(), 0); preorder.clear(); dfs_time = 0; disc[s] = low[s] = ++dfs_time; sign[disc[s]] = -1; tarjan(t, -1); list st_li; vector::iterator> it_ver(n + 1); st_li.push_back(s); st_li.push_back(t); it_ver[disc[s]] = st_li.begin(); it_ver[disc[t]] = next(st_li.begin()); for(int v: preorder) { if(sign[low[v]] == -1) { it_ver[disc[v]] = st_li.insert(it_ver[disc[par[v]]], v); } else { it_ver[disc[v]] = st_li.insert(next(it_ver[disc[par[v]]]), v); } sign[disc[par[v]]] = -sign[low[v]]; } ordering.assign(st_li.begin(), st_li.end()); adj[s].pop_back(); adj[t].pop_back(); return true; } }; ================================================ FILE: graph/two_sat.hpp ================================================ #include using namespace std; class TwoSat { private: vector visited; void dfs1(int u) { visited[u] = true; for(int v: adj[u]) { if(!visited[v]) { dfs1(v); } } top_sort.push_back(u); } void dfs2(int u) { for(int v: radj[u]) { if(comp[v] == -1) { comp[v] = comp[u]; dfs2(v); } } } public: int n; vector> adj, radj; vector comp, comp_ids, top_sort; TwoSat() {} TwoSat(int _n) { init(_n); } void init(int _n) { n = _n; comp_ids.clear(); top_sort.clear(); adj.assign(2 * n, {}); radj.assign(2 * n, {}); } void add_implication(int u, int v, bool neg_u = false, bool neg_v = false) { adj[u << 1 | neg_u].push_back(v << 1 | neg_v); radj[v << 1 | neg_v].push_back(u << 1 | neg_u); } pair> solve() { comp.assign(2 * n, -1); visited.assign(2 * n, false); for(int i = 0; i < 2 * n; i++) { if(!visited[i]) { dfs1(i); } } reverse(top_sort.begin(), top_sort.end()); for(int u: top_sort) { if(comp[u] == -1) { comp[u] = (int)comp_ids.size(); comp_ids.push_back(comp[u]); dfs2(u); } } vector assignment(n); for(int i = 0; i < n; i++) { if(comp[i << 1] == comp[i << 1 | 1]) { return {false, {}}; } assignment[i] = comp[i << 1] > comp[i << 1 | 1]; } return {true, assignment}; } }; ================================================ FILE: math/gauss_bitset.hpp ================================================ #include using namespace std; template class GaussBitset { public: int n_var; vector> rows; vector where; bool solvable = false; GaussBitset(int n_var_) : n_var(n_var_) {} void add_equation(const vector& coeffs, int rhs) { bitset row; for(int i = 0; i < n_var; i++) { if(coeffs[i] % 2) { row[i] = 1; } } row[n_var] = rhs % 2; rows.push_back(row); } void eliminate() { int n_eq = (int)rows.size(); where.assign(n_var, -1); int row = 0; for(int col = 0; col < n_var && row < n_eq; col++) { int sel = -1; for(int i = row; i < n_eq; i++) { if(rows[i][col]) { sel = i; break; } } if(sel == -1) { continue; } swap(rows[sel], rows[row]); where[col] = row; for(int i = 0; i < n_eq; i++) { if(i != row && rows[i][col]) { rows[i] ^= rows[row]; } } row++; } solvable = true; for(int i = row; i < n_eq; i++) { if(rows[i][n_var]) { solvable = false; break; } } } bool has_solution() const { return solvable; } vector free_variables() const { vector fv; for(int v = 0; v < n_var; v++) { if(where[v] == -1) { fv.push_back(v); } } return fv; } vector any_solution() const { vector x(n_var, 0); for(int v = 0; v < n_var; v++) { if(where[v] != -1) { x[v] = rows[where[v]][n_var]; } } return x; } }; ================================================ FILE: old_impl/data_structures/implicit_treap.hpp ================================================ #include using namespace std; random_device rd; mt19937 mt(rd()); struct implicit_treap { struct node { int val, sz, priority, lazy, rev, sum; node *l, *r, *par; node() { lazy = 0; rev = 0; val = 0; sz = 0; priority = 0; l = NULL; r = NULL; par = NULL; } node(int _val) { val = _val; sum = _val; rev = 0; lazy = 0; sz = 1; priority = mt(); l = NULL; r = NULL; par = NULL; } }; typedef node *pnode; pnode root; map position; void clear() { root = NULL; position.clear(); } implicit_treap() { clear(); } int size(pnode p) { return p ? p->sz : 0; } void update_size(pnode &p) { if(p) { p->sz = size(p->l) + size(p->r) + 1; } } void update_parent(pnode &p) { if(!p) { return; } if(p->l) { p->l->par = p; } if(p->r) { p->r->par = p; } } void push(pnode &p) { if(!p) { return; } p->sum += size(p) * p->lazy; p->val += p->lazy; if(p->rev) { swap(p->l, p->r); } if(p->l) { p->l->lazy += p->lazy; p->l->rev ^= p->rev; } if(p->r) { p->r->lazy += p->lazy; p->r->rev ^= p->rev; } p->lazy = 0; p->rev = 0; } void reset(pnode &t) { if(t) { t->sum = t->val; } } void combine(pnode &t, pnode l, pnode r) { if(!l) { t = r; return; } if(!r) { t = l; return; } t->sum = l->sum + r->sum; } void operation(pnode &t) { if(!t) { return; } reset(t); push(t->l); push(t->r); combine(t, t->l, t); combine(t, t, t->r); } void split(pnode t, pnode &l, pnode &r, int k, int add = 0) { if(t == NULL) { l = NULL; r = NULL; return; } push(t); int idx = add + size(t->l); if(idx <= k) { split(t->r, t->r, r, k, idx + 1), l = t; } else { split(t->l, l, t->l, k, add), r = t; } update_parent(t); update_size(t); operation(t); } void merge(pnode &t, pnode l, pnode r) { push(l); push(r); if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->priority > r->priority) { merge(l->r, l->r, r), t = l; } else { merge(r->l, l, r->l), t = r; } update_parent(t); update_size(t); operation(t); } void insert(int pos, int val) { if(root == NULL) { pnode to_add = new node(val); root = to_add; position[val] = root; return; } pnode l, r, mid; mid = new node(val); position[val] = mid; split(root, l, r, pos - 1); merge(l, l, mid); merge(root, l, r); } void erase(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); merge(root, l, r); } int query(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); int answer = mid->sum; merge(r, mid, r); merge(root, l, r); return answer; } void update(int qL, int qR, int val) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); mid->lazy += val; merge(r, mid, r); merge(root, l, r); } void reverse(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); mid->rev ^= 1; merge(r, mid, r); merge(root, l, r); } void cyclic_shift(int qL, int qR, int k) { if(qL == qR) { return; } k %= (qR - qL + 1); pnode l, r, mid, fh, sh; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); split(mid, fh, sh, (qR - qL + 1) - k - 1); merge(mid, sh, fh); merge(r, mid, r); merge(root, l, r); } int get_pos(pnode curr, pnode son = nullptr) { if(!son) { if(curr == root) { return size(curr->l); } else { return size(curr->l) + get_pos(curr->par, curr); } } if(curr == root) { if(son == curr->l) { return 0; } else { return size(curr->l) + 1; } } if(curr->l == son) { return get_pos(curr->par, curr); } else { return get_pos(curr->par, curr) + size(curr->l) + 1; } } int get_pos(int value) { return get_pos(position[value]); } }; implicit_treap build(const vector &a) { implicit_treap t; t.clear(); for(int i = 0; i < (int)a.size(); i++) { t.insert(i, a[i]); } return t; } ================================================ FILE: old_impl/data_structures/implicit_treap_basic.hpp ================================================ #include using namespace std; random_device rd; mt19937 mt(rd()); struct implicit_treap { struct node { int sz, mx, val, prior; node *l, *r; node() { sz = 0; mx = 0; val = 0; prior = 0; l = nullptr; r = nullptr; } node(int _val) { val = _val; mx = val; sz = 1; prior = mt(); l = nullptr; r = nullptr; } }; typedef node *pnode; int size(pnode v) { return v ? v->sz : 0; } void update_size(pnode &v) { if(v) { v->sz = size(v->l) + size(v->r) + 1; } } void reset(pnode &v) { if(v) { v->mx = v->val; } } void combine(pnode &v, pnode l, pnode r) { if(!l) { v = r; return; } if(!r) { v = l; return; } v->mx = max(l->mx, r->mx); } void operation(pnode &v) { if(!v) { return; } reset(v); combine(v, v->l, v); combine(v, v, v->r); } void merge(pnode &t, pnode l, pnode r) { if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->prior > r->prior) { merge(l->r, l->r, r), t = l; } else { merge(r->l, l, r->l), t = r; } update_size(t); operation(t); } void split(pnode t, pnode &l, pnode &r, int k, int add = 0) { if(!t) { l = nullptr; r = nullptr; return; } int idx = add + size(t->l); if(idx <= k) { split(t->r, t->r, r, k, idx + 1), l = t; } else { split(t->l, l, t->l, k, add), r = t; } update_size(t); operation(t); } pnode root; implicit_treap() { root = nullptr; } void insert(int pos, int val) { if(!root) { pnode nw = new node(val); root = nw; return; } pnode l, r, nw = new node(val); split(root, l, r, pos - 1); merge(l, l, nw); merge(root, l, r); } int query_max(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); int ret = mid ? mid->mx : -1; merge(r, mid, r); merge(root, l, r); return ret; } }; ================================================ FILE: old_impl/data_structures/max_count_segment_tree.cpp ================================================ #include using namespace std; const int MAXN = (1 << 20); struct count_max_segment_tree { struct node { int mx, cnt, lazy; node() { mx = -(int)1e9, cnt = 0, lazy = 0; } node(int v) { mx = v; cnt = 1; lazy = 0; } }; node merge(node a, node b) { node ret = node(); ret.mx = max(a.mx, b.mx); ret.cnt = 0; if(ret.mx == a.mx) { ret.cnt += a.cnt; } if(ret.mx == b.mx) { ret.cnt += b.cnt; } return ret; } node tr[MAXN << 2]; void push(int l, int r, int idx) { if(tr[idx].lazy) { tr[idx].mx += tr[idx].lazy; if(l != r) { tr[2 * idx + 1].lazy += tr[idx].lazy; tr[2 * idx + 2].lazy += tr[idx].lazy; } tr[idx].lazy = 0; } } void init(int l, int r, int idx) { if(l == r) { tr[idx] = node(-l); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void add(int ql, int qr, int v, int l, int r, int idx) { push(l, r, idx); if(qr < l || ql > r) { return; } if(ql <= l && r <= qr) { tr[idx].lazy += v; push(l, r, idx); return; } int mid = (l + r) >> 1; add(ql, qr, v, l, mid, 2 * idx + 1); add(ql, qr, v, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int ql, int qr, int l, int r, int idx) { push(l, r, idx); if(qr < l || ql > r) { return node(); } if(ql <= l && r <= qr) { return tr[idx]; } int mid = (l + r) >> 1; return merge( query(ql, qr, l, mid, 2 * idx + 1), query(ql, qr, mid + 1, r, 2 * idx + 2) ); } void walk(int l, int r, int idx) { push(l, r, idx); if(l == r) { cout << l << ": " << "{" << tr[idx].mx << " " << tr[idx].cnt << " lazy=" << tr[idx].lazy << "}" << " "; return; } int mid = (l + r) >> 1; walk(l, mid, 2 * idx + 1); walk(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } }; ================================================ FILE: old_impl/data_structures/merging_segment_tree.cpp ================================================ #include using namespace std; struct node { int sz; node *l, *r; node() { sz = 0; l = r = nullptr; } node(int _s) { sz = _s; l = r = nullptr; } }; typedef node *pnode; inline int size(pnode p) { return p ? p->sz : 0; } inline void update_size(pnode &p) { if(!p) { return; } p->sz = 1 + size(p->l) + size(p->r); } pnode init(int val, int l, int r) { pnode ret = new node(1); if(l == r) { return ret; } int mid = (l + r) >> 1; if(val <= mid) { ret->l = init(val, l, mid); } else { ret->r = init(val, mid + 1, r); } return ret; } pnode merge(pnode l, pnode r) { if(!l) { return r; } if(!r) { return l; } l->l = merge(l->l, r->l); l->r = merge(l->r, r->r); l->sz += r->sz; return l; } pair split(pnode &t, int k) { if(!t) { return {nullptr, nullptr}; } pair ret, tmp; ret.second = new node(); int L = size(t->l); if(L < k) { tmp = split(t->r, k - L); ret.second = tmp.second; ret.first = t; ret.first->r = tmp.first; } else { tmp = split(t->l, k); ret.first = tmp.first; ret.second = t; ret.second->l = tmp.second; } update_size(ret.first); update_size(ret.second); return ret; } int kth(pnode t, int k, int l, int r) { if(!t) { return -1; } if(l == r) { return l; } int mid = (l + r) >> 1, L = size(t->l); if(L < k) { return kth(t->r, k - L, l, mid); } else { return kth(t->l, k, mid + 1, r); } } ================================================ FILE: old_impl/data_structures/min_segment_tree.cpp ================================================ #include #define endl '\n' #define SZ(x) ((int)x.size()) #define ALL(V) V.begin(), V.end() #define L_B lower_bound #define U_B upper_bound #define pb push_back using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } const int MAXN = (1 << 20); struct segment_tree_min { struct node { int mn, pos; node() { mn = (int)1e9; pos = -1; } node(int v, int i) { mn = v; pos = i; } }; node merge(node a, node b) { node ret = a; if(chkmin(ret.mn, b.mn)) ret.pos = b.pos; return ret; } node tr[MAXN << 2]; void init(int l, int r, int idx) { if(l == r) { tr[idx] = node(); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int pos, int v, int l, int r, int idx) { if(l == r) { tr[idx] = node(v, pos); return; } int mid = (l + r) >> 1; if(pos <= mid) update(pos, v, l, mid, 2 * idx + 1); else update(pos, v, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int ql, int qr, int l, int r, int idx) { if(ql > r || qr < l) { return node(); } if(ql <= l && r <= qr) { return tr[idx]; } int mid = (l + r) >> 1; return merge(query(ql, qr, l, mid, 2 * idx + 1), query(ql, qr, mid + 1, r, 2 * idx + 2)); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/monotonous_queue.cpp ================================================ #include #define endl '\n' using namespace std; template inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; } template inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; } const int MAXN = (1 << 20); template struct monotonous_queue_max { int len, current_position; deque > Q; monotonous_queue_max() { Q.clear(); current_position = 0; len = 0; } void init(int _l) { len = _l; current_position = 0; Q.clear(); } void push_back(T x) { while(!Q.empty() && current_position - Q.front().second >= len) Q.pop_front(); while(!Q.empty() && x >= Q.back().first) Q.pop_back(); Q.push_back({x, current_position++}); } T query() { if(Q.empty()) return -(T)1e9; return Q.front().first; } }; template struct monotonous_queue_min { int len, current_position; deque > Q; monotonous_queue_min() { Q.clear(); current_position = 0; len = 0; } void init(int _l) { len = _l; current_position = 0; Q.clear(); } void push_back(T x) { while(!Q.empty() && current_position - Q.front().second >= len) Q.pop_front(); while(!Q.empty() && x <= Q.back().first) Q.pop_back(); Q.push_back({x, current_position++}); } T query() { if(Q.empty()) return (T)1e9; return Q.front().first; } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/persistent_segment_tree.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct node { int sum; node *l, *r; node() { l = nullptr; r = nullptr; sum = 0; } node(int x) { sum = x; l = nullptr; r = nullptr; } }; node* merge(node* l, node* r) { node* ret = new node(0); ret->sum = l->sum + r->sum; ret->l = l; ret->r = r; return ret; } node* init(int l, int r) { if(l == r) { return (new node(0)); } int mid = (l + r) >> 1; return merge(init(l, mid), init(mid + 1, r)); } node* update(int pos, int val, int l, int r, node* nd) { if(pos < l || pos > r) { return nd; } if(l == r) { return (new node(val)); } int mid = (l + r) >> 1; return merge( update(pos, val, l, mid, nd->l), update(pos, val, mid + 1, r, nd->r) ); } int query(int qL, int qR, int l, int r, node* nd) { if(qL <= l && r <= qR) { return nd->sum; } if(qL > r || qR < l) { return 0; } int mid = (l + r) >> 1; return query(qL, qR, l, mid, nd->l) + query(qL, qR, mid + 1, r, nd->r); } int get_kth(int k, int l, int r, node* nd) { if(l == r) { return l; } int mid = (l + r) >> 1; if(nd->l->sum < k) { return get_kth(k - nd->l->sum, mid + 1, r, nd->r); } else { return get_kth(k, l, mid, nd->l); } } void read() {} node* t[MAXN]; void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/persistent_segment_tree_lazy.cpp ================================================ #include #define endl '\n' using namespace std; template inline void chkmax(T &x, const T2 &y) { if(x < y) { x = y; } } template inline void chkmin(T &x, const T2 &y) { if(x > y) { x = y; } } const int MAXN = (1 << 20); int n, q; int a[MAXN]; struct node { int64_t lazy, sum; node *l, *r; node() { lazy = sum = 0; l = r = nullptr; } node(int64_t val) { lazy = 0; sum = val; l = r = nullptr; } }; typedef node *pnode; pnode merge(pnode a, pnode b) { pnode ret = new node(); ret->sum = a->sum + b->sum; ret->l = a; ret->r = b; return ret; } pnode cop(pnode b) { if(!b) { return nullptr; } pnode ret = new node(); ret->sum = b->sum; ret->lazy = b->lazy; ret->l = b->l; ret->r = b->r; return ret; } void push(int l, int r, pnode &ver) { if(!ver->lazy) { return; } ver->sum += (r - l + 1) * 1ll * ver->lazy; ver->l = cop(ver->l); ver->r = cop(ver->r); if(l != r) { ver->l->lazy += ver->lazy; ver->r->lazy += ver->lazy; } ver->lazy = 0; } pnode init(int l, int r) { if(l == r) { return new node(a[l]); } int mid = (l + r) >> 1; return merge(init(l, mid), init(mid + 1, r)); } pnode update(int qL, int qR, int val, int l, int r, pnode prv) { push(l, r, prv); if(qL <= l && r <= qR) { pnode ret = cop(prv); ret->lazy += val; push(l, r, ret); return ret; } if(qL > r || qR < l) { return prv; } int mid = (l + r) >> 1; return merge( update(qL, qR, val, l, mid, prv->l), update(qL, qR, val, mid + 1, r, prv->r) ); } int64_t query(int qL, int qR, int l, int r, pnode nd) { push(l, r, nd); if(qL > r || qR < l) { return 0; } if(qL <= l && r <= qR) { return nd->sum; } int mid = (l + r) >> 1; return query(qL, qR, l, mid, nd->l) + query(qL, qR, mid + 1, r, nd->r); } void read() { cin >> n >> q; for(int i = 0; i < n; i++) { cin >> a[i]; } } pnode root[MAXN]; void solve() { root[1] = init(0, n - 1); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/persistent_treap.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); random_device rd; mt19937 mt(rd()); struct persistent_treap { struct node { int sz, mx, val; node *l, *r; node() { sz = 0; mx = 0; val = 0; l = nullptr; r = nullptr; } node(int _val) { val = _val; mx = val; sz = 1; l = nullptr; r = nullptr; } }; typedef node* pnode; pnode copy_node(pnode prv) { if(!prv) return nullptr; pnode ret = new node(); ret->l = prv->l; ret->r = prv->r; ret->val = prv->val; ret->sz = prv->sz; ret->mx = prv->mx; return ret; } int size(pnode v) { return v ? v->sz : 0; } void update_size(pnode &v) { if(v) v->sz = size(v->l) + size(v->r) + 1; } void reset(pnode &v) { if(v) v->mx = v->val; } bool hey(int a, int b) { return (int)mt() % (a + b) < a; } void combine(pnode &v, pnode l, pnode r) { if(!l) { v = r; return; } if(!r) { v = l; return; } v->mx = max(l->mx, r->mx); } void operation(pnode &v) { if(!v) return; reset(v); combine(v, v->l, v); combine(v, v, v->r); } void merge(pnode &t, pnode l, pnode r) { if(!l) { t = copy_node(r); return; } if(!r) { t = copy_node(l); return; } if(hey(size(l), size(r))) { t = copy_node(l); merge(t->r, l->r, r); } else { t = copy_node(r); merge(t->l, l, r->l); } update_size(t); operation(t); } void split(pnode t, pnode &l, pnode &r, int k, int add = 0) { if(!t) { l = nullptr; r = nullptr; return; } int idx = add + size(t->l); if(idx <= k) { l = copy_node(t); split(t->r, l->r, r, k, idx + 1); update_size(l); operation(l); } else { r = copy_node(t); split(t->l, l, r->l, k, add); update_size(r); operation(r); } update_size(t); operation(t); } pnode root; persistent_treap() { root = nullptr; } void insert(int pos, int val) { if(!root) { pnode nw = new node(val); root = nw; return; } pnode l, r, nw = new node(val); split(root, l, r, pos - 1); merge(l, l, nw); merge(root, l, r); } int query_max(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); int ret = mid ? mid->mx : -1; merge(r, mid, r); merge(root, l, r); return ret; } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/persistent_treap_lazy.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); random_device rd; mt19937 mt(rd()); struct persistent_treap { struct node { int sz, mx, val, lazy; node *l, *r; node() { sz = 0; mx = 0; lazy = 0; val = 0; l = nullptr; r = nullptr; } node(int _val) { lazy = 0; val = _val; mx = val; sz = 1; l = nullptr; r = nullptr; } }; typedef node* pnode; pnode copy_node(pnode prv) { if(!prv) return nullptr; pnode ret = new node(); ret->l = prv->l; ret->r = prv->r; ret->val = prv->val; ret->sz = prv->sz; ret->mx = prv->mx; ret->lazy = prv->lazy; return ret; } int size(pnode v) { return v ? v->sz : 0; } void update_size(pnode &v) { if(v) v->sz = size(v->l) + size(v->r) + 1; } void reset(pnode &v) { if(v) v->mx = v->val; } bool hey(int a, int b) { return (int)mt() % (a + b) < a; } void push(pnode &t) { if(t && t->lazy) { t->mx += t->lazy; t->val += t->lazy; if(t->l) t->l = copy_node(t->l), t->l->lazy += t->lazy; if(t->r) t->r = copy_node(t->r), t->r->lazy += t->lazy; t->lazy = 0; } } void combine(pnode &v, pnode l, pnode r) { if(!l) { v = r; return; } if(!r) { v = l; return; } v->mx = max(l->mx, r->mx); } void operation(pnode &v) { if(!v) return; push(v->l); push(v->r); reset(v); combine(v, v->l, v); combine(v, v, v->r); } void merge(pnode &t, pnode l, pnode r) { push(l), push(r); if(!l) { t = copy_node(r); return; } if(!r) { t = copy_node(l); return; } if(hey(size(l), size(r))) { t = copy_node(l); merge(t->r, l->r, r); } else { t = copy_node(r); merge(t->l, l, r->l); } update_size(t); operation(t); } void split(pnode t, pnode &l, pnode &r, int k, int add = 0) { push(t); if(!t) { l = nullptr; r = nullptr; return; } int idx = add + size(t->l); if(idx <= k) { l = copy_node(t); split(t->r, l->r, r, k, idx + 1); update_size(l); operation(l); } else { r = copy_node(t); split(t->l, l, r->l, k, add); update_size(r); operation(r); } update_size(t); operation(t); } pnode root; persistent_treap() { root = nullptr; } void insert(int pos, int val) { if(!root) { pnode nw = new node(val); root = nw; return; } pnode l, r, nw = new node(val); split(root, l, r, pos - 1); merge(l, l, nw); merge(root, l, r); } int query_max(int qL, int qR) { pnode l, r, mid; split(root, l, r, qL - 1); split(r, mid, r, qR - qL); int ret = mid ? mid->mx : -1; merge(r, mid, r); merge(root, l, r); return ret; } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 18); int n, m; int a[MAXN]; struct node { int sum; node() { sum = 0; } node(int val) { sum = val; } }; node merge(node l, node r) { node temp; temp.sum = l.sum + r.sum; return temp; } struct segment_tree { node tr[MAXN << 2]; void init(int l, int r, int idx) { if(l == r) { tr[idx] = node(a[l]); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int pos, int val, int l, int r, int idx) { if(l > pos || r < pos) return; if(l == r && l == pos) { tr[idx].sum += val; return; } int mid = (l + r) >> 1; update(pos, val, l, mid, 2 * idx + 1); update(pos, val, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int qL, int qR, int l, int r, int idx) { if(l > qR || r < qL) { return node(); } if(qL <= l && r <= qR) { return tr[idx]; } int mid = (l + r) >> 1; return merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2)); } }; void read() { cin >> n >> m; for(int i = 0; i < n; i++) cin >> a[i]; } segment_tree t; void solve() { t.init(0, n - 1, 0); for(int i = 0; i < m; i++) { int l, r; cin >> l >> r; cout << t.query(l, r, 0, n - 1, 0).sum << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_AP.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 18); int n, m; int a[MAXN]; struct node_ap { int sum, lazy, lazy_ap; node_ap() {sum = 0; lazy = 0; lazy_ap = 0;} node_ap(int val) { sum = val; lazy = 0; lazy_ap = 0; } }; node_ap temp, broken; node_ap merge(node_ap l, node_ap r) { temp.sum = l.sum + r.sum; temp.lazy = 0; temp.lazy_ap = 0; return temp; } struct segment_tree_ap { node_ap tr[4 * MAXN]; void update(int l, int r, int idx) { if(tr[idx].lazy) { tr[idx].sum += (r - l + 1) * tr[idx].lazy; if(l != r) { tr[2 * idx + 1].lazy += tr[idx].lazy; tr[2 * idx + 2].lazy += tr[idx].lazy; } tr[idx].lazy = 0; } if(tr[idx].lazy_ap) { int mid = (l + r) >> 1; tr[idx].sum += ((r - l + 1) * (r - l + 2) / 2) * tr[idx].lazy_ap; if(l != r) { tr[2 * idx + 1].lazy_ap += tr[idx].lazy_ap; tr[2 * idx + 2].lazy_ap += tr[idx].lazy_ap; tr[2 * idx + 2].lazy += tr[idx].lazy_ap * (mid - l + 1); } tr[idx].lazy_ap = 0; } } void init(int l, int r, int idx) { if(l == r) { tr[idx] = node_ap(a[l]); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int qL, int qR, int val, int prog, int l, int r, int idx) { update(l, r, idx); if(qL > r || l > qR) return; if(qL <= l && r <= qR) { tr[idx].lazy += val + (l - qL) * prog; tr[idx].lazy_ap += prog; update(l, r, idx); return; } int mid = (l + r) >> 1; update(qL, qR, val, prog, l, mid, 2 * idx + 1); update(qL, qR, val, prog, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node_ap query(int qL, int qR, int l, int r, int idx) { update(l, r, idx); if(l > qR || r < qL) return broken; if(qL <= l && r <= qR) return tr[idx]; int mid = (l + r) >> 1; return merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2)); } }; void read() { } segment_tree_ap t; void solve() { t.init(0, n - 1, 0); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_add_mult.cpp ================================================ #include #define endl '\n' //#pragma GCC optimize ("O3") //#pragma GCC target ("sse4") using namespace std; template inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; } template inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; } const int MAXN = (1 << 20); const int mod = (int)1e9 + 7; struct node { int sum, lazy, mult; node() {sum = 0; mult = 1; lazy = 0;} node(int val) { sum = val; lazy = 0; mult = 1; } }; node temp, broken; node merge(node l, node r) { temp.sum = (l.sum + r.sum) % mod; temp.lazy = 0; temp.mult = 1; return temp; } struct segment_tree { node tr[4 * MAXN]; void push(int l, int r, int idx) { if(tr[idx].mult != 1) { tr[idx].sum = (tr[idx].sum * 1ll * tr[idx].mult) % mod; tr[idx].sum %= mod; if(l != r) { tr[2 * idx + 1].mult = (tr[2 * idx + 1].mult * 1ll * tr[idx].mult) % mod; tr[2 * idx + 2].mult = (tr[2 * idx + 2].mult * 1ll * tr[idx].mult) % mod; tr[2 * idx + 1].lazy = (tr[2 * idx + 1].lazy * 1ll * tr[idx].mult) % mod; tr[2 * idx + 2].lazy = (tr[2 * idx + 2].lazy * 1ll * tr[idx].mult) % mod; } tr[idx].mult = 1; } if(tr[idx].lazy) { tr[idx].sum += ((r - l + 1) * 1ll * tr[idx].lazy) % mod; tr[idx].sum %= mod; if(l != r) { tr[2 * idx + 1].lazy = (tr[2 * idx + 1].lazy + tr[idx].lazy) % mod; tr[2 * idx + 2].lazy = (tr[2 * idx + 2].lazy + tr[idx].lazy) % mod; } tr[idx].lazy = 0; } } void init(int l, int r, int idx) { if(l == r) { tr[idx] = node(); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void mult(int qL, int qR, int x, int l, int r, int idx) { push(l, r, idx); if(qL > r || l > qR) return; if(qL <= l && r <= qR) { tr[idx].mult = (tr[idx].mult * 1ll * x) % mod; push(l, r, idx); return; } int mid = (l + r) >> 1; mult(qL, qR, x, l, mid, 2 * idx + 1); mult(qL, qR, x, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void add(int qL, int qR, int x, int l, int r, int idx) { push(l, r, idx); if(qL > r || l > qR) return; if(qL <= l && r <= qR) { tr[idx].lazy = (tr[idx].lazy + x) % mod; push(l, r, idx); return; } int mid = (l + r) >> 1; add(qL, qR, x, l, mid, 2 * idx + 1); add(qL, qR, x, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int qL, int qR, int l, int r, int idx) { push(l, r, idx); if(l > qR || r < qL) return broken; if(qL <= l && r <= qR) return tr[idx]; int mid = (l + r) >> 1; return merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2)); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_fast.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct node { int mx; node() { mx = -1e9; } node(int val) { mx = val; } }; node temp; node merge(node l, node r) { temp.mx = max(l.mx, r.mx); return temp; } struct segment_tree { int n; node t[2 * MAXN]; void init(int sz) { n = sz; for(int i = 0; i < n; i++) { t[i + n] = node(); } for(int i = n - 1; i > 0; --i) { t[i] = merge(t[i << 1], t[i << 1 | 1]); } } void modify(int p, const node &value) { for(t[p += n] = value; p >>= 1;) { t[p] = merge(t[p << 1], t[p << 1 | 1]); } } node query(int l, int r) { node resl, resr; for(l += n, r += n; l < r; l >>= 1, r >>= 1) { if(l & 1) { resl = merge(resl, t[l++]); } if(r & 1) { resr = merge(t[--r], resr); } } return merge(resl, resr); } }; void read() {} segment_tree t; void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_lazy_min.cpp ================================================ #include #include using namespace std; template class segment_tree_min { private: static const T max_possible_value = std::numeric_limits::max(); struct node { T mn; int pos; node() { mn = max_possible_value; pos = -1; } node(T val, int p) { mn = val; pos = p; } }; node merge(node l, node r) { node temp; temp.mn = min(l.mn, r.mn); if(l.mn == temp.mn) { temp.pos = l.pos; } else { temp.pos = r.pos; } return temp; } void push(int l, int r, int idx) { if(lazy[idx]) { tr[idx].mn += lazy[idx]; if(l != r) { lazy[2 * idx + 1] += lazy[idx]; lazy[2 * idx + 2] += lazy[idx]; } lazy[idx] = 0; } } int n; vector lazy; vector tr; void init(int l, int r, int idx, const vector &a) { if(l == r) { tr[idx] = node(a[l], l); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1, a); init(mid + 1, r, 2 * idx + 2, a); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int qL, int qR, T val, int l, int r, int idx) { push(l, r, idx); if(qL > r || l > qR) { return; } if(qL <= l && r <= qR) { lazy[idx] += val; push(l, r, idx); return; } int mid = (l + r) >> 1; update(qL, qR, val, l, mid, 2 * idx + 1); update(qL, qR, val, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int qL, int qR, int l, int r, int idx) { push(l, r, idx); if(l > qR || r < qL) { return node(); } if(qL <= l && r <= qR) { return tr[idx]; } int mid = (l + r) >> 1; return merge( query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2) ); } public: void init(const vector &a) { n = a.size(); tr.resize(4 * n); lazy.assign(4 * n, 0); init(0, n - 1, 0, a); } void update(int qL, int qR, int val) { if(qR < qL) { return; } update(qL, qR, val, 0, n - 1, 0); } node query(int qL, int qR) { if(qR < qL) { return node(); } return query(qL, qR, 0, n - 1, 0); } }; int n, m; vector a; void read() { cin >> n >> m; a.resize(n); for(int i = 0; i < n; i++) { cin >> a[i]; } } segment_tree_min t; void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_lazy_sum.cpp ================================================ #include using namespace std; template class segment_tree_sum { private: struct node { T sum; node() { sum = 0; } node(T val) { sum = val; } }; node merge(node l, node r) { node temp; temp.sum = l.sum + r.sum; return temp; } void push(int l, int r, int idx) { if(lazy[idx]) { tr[idx].sum += lazy[idx] * (r - l + 1); if(l != r) { lazy[2 * idx + 1] += lazy[idx]; lazy[2 * idx + 2] += lazy[idx]; } lazy[idx] = 0; } } int n; vector lazy; vector tr; void init(int l, int r, int idx, const vector &a) { if(l == r) { tr[idx] = node(a[l]); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1, a); init(mid + 1, r, 2 * idx + 2, a); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int qL, int qR, T val, int l, int r, int idx) { push(l, r, idx); if(qL > r || l > qR) { return; } if(qL <= l && r <= qR) { lazy[idx] += val; push(l, r, idx); return; } int mid = (l + r) >> 1; update(qL, qR, val, l, mid, 2 * idx + 1); update(qL, qR, val, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } node query(int qL, int qR, int l, int r, int idx) { push(l, r, idx); if(l > qR || r < qL) { return node(); } if(qL <= l && r <= qR) { return tr[idx]; } int mid = (l + r) >> 1; return merge( query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2) ); } public: void init(vector a) { n = a.size(); tr.resize(4 * n); lazy.assign(4 * n, 0); init(0, n - 1, 0, a); } void update(int qL, int qR, int val) { if(qR < qL) { return; } update(qL, qR, val, 0, n - 1, 0); } node query(int qL, int qR) { if(qR < qL) { return node(); } return query(qL, qR, 0, n - 1, 0); } }; int n, m; vector a; void read() { cin >> n >> m; a.resize(n); for(int i = 0; i < n; i++) { cin >> a[i]; } } segment_tree_sum t; void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_nonzero.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct segment_tree { int ord[4 * MAXN], sum[4 * MAXN]; void init(int l, int r, int idx) { if(l == r) { ord[idx] = 0; sum[idx] = 0; return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); if(ord[idx]) sum[idx] = (r - l + 1); else sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2]; } void update(int qL, int qR, int val, int l, int r, int idx) { if(r < qL || l > qR) return; if(qL <= l && r <= qR) { ord[idx] += val; if(ord[idx] > 0) sum[idx] = (r - l + 1); else sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2]; return; } int mid = (l + r) >> 1; update(qL, qR, val, l, mid, 2 * idx + 1); update(qL, qR, val, mid + 1, r, 2 * idx + 2); if(ord[idx] > 0) sum[idx] = (r - l + 1); else sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2]; } }; void read() { } segment_tree t; void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/segment_tree_with_binary_search.cpp ================================================ #include #define endl '\n' using namespace std; template inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; } template inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; } const int MAXN = (1 << 20); const int inf = (int)1e9 + 42; struct node { int mn; node() { mn = inf; } node(int val) { mn = val; } }; node temp, broken; node merge(node l, node r) { temp.mn = min(l.mn, r.mn); return temp; } int bound_L[MAXN], bound_R[MAXN]; struct segment_tree { node tr[4 * MAXN]; void init(int l, int r, int idx) { bound_L[idx] = l; bound_R[idx] = r; if(l == r) { tr[idx] = node(inf); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int pos, int val, int l, int r, int idx) { if(l > pos || r < pos) return; if(l == r && l == pos) { tr[idx].mn = val; return; } int mid = (l + r) >> 1; update(pos, val, l, mid, 2 * idx + 1); update(pos, val, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void get_nodes(int qL, int qR, int l, int r, int idx, vector &li) { if(l > qR || r < qL) return; if(qL <= l && r <= qR) { li.push_back(idx); return; } int mid = (l + r) >> 1; get_nodes(qL, qR, l, mid, 2 * idx + 1, li); get_nodes(qL, qR, mid + 1, r, 2 * idx + 2, li); } int get_right(int l, int r, int idx, int X) { if(l == r) return l; int mid = (l + r) >> 1; if(tr[2 * idx + 1].mn <= X) return get_right(l, mid, 2 * idx + 1, X); else return get_right(mid + 1, r, 2 * idx + 2, X); } int get_left(int l, int r, int idx, int X) { if(l == r) return l; int mid = (l + r) >> 1; if(tr[2 * idx + 2].mn <= X) return get_left(mid + 1, r, 2 * idx + 2, X); else return get_left(l, mid, 2 * idx + 1, X); } }; int n; segment_tree t; int get_left(int pos, int val) { vector li; t.get_nodes(1, pos, 1, n, 0, li); reverse(li.begin(), li.end()); for(int it: li) if(t.tr[it].mn <= val) return t.get_left(bound_L[it], bound_R[it], it, val); return 0; } int get_right(int pos, int val) { vector li; t.get_nodes(pos, n, 1, n, 0, li); for(int it: li) if(t.tr[it].mn <= val) return t.get_right(bound_L[it], bound_R[it], it, val); return n + 1; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/data_structures/treap.cpp ================================================ #include using namespace std; random_device rd; mt19937 mt(rd()); struct node { int sz, prior, value; node *l, *r; node() { value = 0; sz = 0; prior = 0; l = nullptr; r = nullptr; } node(int v) { value = v; sz = 1; prior = mt(); l = nullptr; r = nullptr; } }; typedef node *pnode; inline int size(pnode v) { return v ? v->sz : 0; } void pull(pnode &v) { if(!v) { return; } v->sz = size(v->l) + size(v->r) + 1; } void merge(pnode &t, pnode l, pnode r) { if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->prior > r->prior) { merge(l->r, l->r, r), t = l; } else { merge(r->l, l, r->l), t = r; } pull(t); } void split(pnode t, pnode &l, pnode &r, int k) { if(!t) { l = nullptr; r = nullptr; return; } if(t->value <= k) { split(t->r, t->r, r, k), l = t; } else { split(t->l, l, t->l, k), r = t; } pull(t); } void merge_op(pnode &t, pnode l, pnode r) { if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->prior < r->prior) { swap(l, r); } pnode L, R; split(r, L, R, l->value - mt() % 2); merge_op(l->r, l->r, R); merge_op(l->l, L, l->l); t = l; pull(t); } void split_sz(pnode t, pnode &l, pnode &r, int k, int add = 0) { if(!t) { l = nullptr; r = nullptr; return; } int idx = add + size(t->l); if(idx <= k) { split_sz(t->r, t->r, r, k, idx + 1), l = t; } else { split_sz(t->l, l, t->l, k, add), r = t; } pull(t); } void read() {} void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/geometry/closest_points.cpp ================================================ #include #define endl '\n' #define int long long using namespace std; const int MAXN = (1 << 20); const double eps = 0.000001; const int inf = (int)1e17 + 42; struct point { int x, y; point() {x = 0; y = 0;} point(int _x, int _y) { x = _x; y = _y; } }; bool cmpbyx(point a, point b) { if(a.x == b.x) return a.y < b.y; return a.x < b.x; } bool cmpbyy(point a, point b) { if(a.y == b.y) return a.x < b.x; return a.y < b.y; } int n; int a[MAXN]; void read() { cin >> n; for(int i = 1; i <= n; i++) cin >> a[i]; } vector p; int dist(point p_i, point p_j) { return (p_i.x - p_j.x) * (p_i.x - p_j.x) + (p_i.y - p_j.y) * (p_i.y - p_j.y); } int rec(int l, int r) { if(l == r) return inf; int ret, mid = (l + r) >> 1; double d; ret = min(rec(l, mid), rec(mid + 1, r)); d = sqrt(ret); vector c; for(int i = l; i <= r; i++) if(abs(p[i].x - p[mid].x) <= d) c.push_back(p[i]); sort(c.begin(), c.end(), cmpbyy); for(int i = 0; i < c.size(); i++) for(int j = i + 1; j < c.size() && (c[j].y - c[i].y) <= d; j++) { ret = min(ret, dist(c[i], c[j])); d = sqrt(ret); } return ret; } void solve() { a[0] = 0; for(int i = 1; i <= n; i++) a[i] += a[i - 1]; for(int i = 1; i <= n; i++) p.push_back(point(i, a[i])); sort(p.begin(), p.end(), cmpbyx); int ans = rec(0, n - 1); cout << ans << endl; } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/geometry/convex_hull.cpp ================================================ #include #define endl '\n' #define double long double using namespace std; const int MAXN = (1 << 20); const double dinf = (double)1e17; const double eps = 0.00000000000001; struct point { double x, y; point() {x = 0; y = 0;} point(double _x, double _y) { x = _x; y = _y; } }; bool cmp(point a, point b) { if(a.x == b.x) return a.y < b.y; return a.x < b.x; } double slope(point a, point b) { double deltax = b.x - a.x; double deltay = b.y - a.y; if(max(-deltax, deltax) < eps) return (((deltax < 0) ? (-1) : 1) * deltay < 0) ? (-dinf) : (dinf); return deltay / deltax; } struct convex_hull { vector st; convex_hull() {st.clear();} void compute_hull(vector vec) { sort(vec.begin(), vec.end(), cmp); for(int i = 0; i < (int)vec.size(); i++) { while(st.size() >= 2 && slope(st[st.size() - 2], vec[i]) >= slope(st[st.size() - 2], st[st.size() - 1])) st.pop_back(); st.push_back(vec[i]); } st.pop_back(); int k = st.size(); for(int i = vec.size() - 1; i >= 0; i--) { while(st.size() - k >= 2 && slope(vec[i], st[st.size() - 2]) >= slope(st[st.size() - 1], st[st.size() - 2])) st.pop_back(); st.push_back(vec[i]); } st.pop_back(); } }; int n; vector a; void read() { cin >> n; for(int i = 0; i < n; i++) { double x, y; cin >> x >> y; a.push_back(point(x, y)); } } convex_hull hull; void solve() { hull.compute_hull(a); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/geometry/dynamic_upper_hull.cpp ================================================ #include #define endl '\n' #define SZ(x) ((int)x.size()) #define ALL(V) V.begin(), V.end() #define L_B lower_bound #define U_B upper_bound #define pb push_back using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } const int MAXN = (int)5e4 + 42; struct PT { int x, y; PT() { x = y = 0; } PT(int _x, int _y) { x = _x; y = _y; } int64_t operator&(const PT &other) { return x * 1ll * other.y - y * 1ll * other.x; } PT operator+(const PT &other) const { return PT(x + other.x, y + other.y); } PT operator-(const PT &other) const { return PT(x - other.x, y - other.y); } }; random_device rd; mt19937 mt(rd()); int64_t eval(PT L, PT R) { return (L.y + R.y) * 1ll * (R.x - L.x); } struct node { PT pnt; int prior, sz; int64_t answer; node *l, *r, *leftmost, *rightmost, *prv; node() { sz = 0; answer = prior = 0; leftmost = rightmost = prv = l = r = nullptr; pnt = PT(); } node(PT a) {leftmost = rightmost = this; sz = 1; answer = 0; pnt = a; prior = mt(); prv = l = r = nullptr; } }; using pnode = node*; inline int size(pnode &t) { return t ? t->sz : 0; } void pull(pnode &t) { if(!t) return; t->answer = 0; t->sz = size(t->l) + size(t->r) + 1; t->leftmost = t->rightmost = t; t->prv = nullptr; if(t->l) { t->answer += t->l->answer; t->answer += eval(t->l->rightmost->pnt, t->pnt); t->prv = t->l->rightmost; t->leftmost = t->l->leftmost; } if(t->r) { t->answer += t->r->answer; t->answer += eval(t->pnt, t->r->leftmost->pnt); t->r->leftmost->prv = t; t->rightmost = t->r->rightmost; } } void merge(pnode &t, pnode l, pnode r) { if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->prior > r->prior) merge(l->r, l->r, r), t = l; else merge(r->l, l, r->l), t = r; pull(t); } void split_x(pnode t, pnode &l, pnode &r, int k) { if(!t) { l = r = nullptr; return; } if(t->pnt.x <= k) split_x(t->r, t->r, r, k), l = t; else split_x(t->l, l, t->l, k), r = t; pull(t); } void split_sz(pnode t, pnode &l, pnode &r, int k, int add = 0) { if(!t) { l = r = nullptr; return; } int idx = size(t->l) + add; if(idx <= k) split_sz(t->r, t->r, r, k, idx + 1), l = t; else split_sz(t->l, l, t->l, k, add), r = t; pull(t); } int q, T; int tin[MAXN], tout[MAXN], n = 0; PT p[MAXN]; void read() { cin >> q >> T; for(int i = 0; i < q; i++) { char type; cin >> type; if(type == '+') { tin[n++] = i; tout[n - 1] = q - 1; int _p, _t; cin >> _p >> _t; p[n - 1] = PT(_t, _p); } else { int idx = 0; cin >> idx; tout[idx] = i - 1; } } } pnode root; vector li[4 * MAXN]; int64_t answer[MAXN]; void add(int ql, int qr, int i, int l, int r, int idx) { if(r < ql || qr < l) return; if(ql <= l && r <= qr) { li[idx].pb(i); return; } int mid = (l + r) >> 1; add(ql, qr, i, l, mid, 2 * idx + 1); add(ql, qr, i, mid + 1, r, 2 * idx + 2); } int64_t cww(const PT &a, const PT &b, const PT &c) { return (b - a) & (c - a); } int find_pref(pnode t, PT R) { if(!t) return 0; if(!t->prv || cww(t->prv->pnt, t->pnt, R) < 0) return max(t->pnt.x, find_pref(t->r, R)); else return find_pref(t->l, R); } int find_suff(pnode t, PT L) { if(!t) return 0; if(t->prv == nullptr) return find_suff(t->r, L); else { if(cww(L, t->prv->pnt, t->pnt) >= 0) return max(t->prv->pnt.x, find_suff(t->r, L)); else return find_suff(t->l, L); } } pair add(pnode &t, PT pnt) { pnode l, r, nw = new node(pnt); split_x(t, l, r, pnt.x); if(cww(l->rightmost->pnt, pnt, r->leftmost->pnt) >= 0) { merge(t, l, r); return {false, nullptr}; } int good_pref = find_pref(l, pnt), bad_pref = find_suff(r, pnt); pnode rem_l, rem_r; split_x(l, l, rem_l, good_pref); split_x(r, rem_r, r, bad_pref); //cout << "Adding " << pnt.x << " " << pnt.y << " -> " << good_pref << " " << bad_pref << endl << flush; //cout << "Sizes: " << size(l) << " " << size(r) << endl << flush; assert(l != nullptr); assert(r != nullptr); pnode ret; merge(t, l, nw); merge(t, t, r); merge(ret, rem_l, rem_r); return {true, ret}; } void solve(int l, int r, int idx) { stack > ST; for(int i: li[idx]) { pair q = add(root, p[i]); if(q.first == true) ST.push({p[i].x, q.second}); } if(l == r) answer[l] = root->answer; else { int mid = (l + r) >> 1; solve(l, mid, 2 * idx + 1); solve(mid + 1, r, 2 * idx + 2); } while(!ST.empty()) { auto mid = ST.top(); ST.pop(); pnode L, R, dummy; split_x(root, L, R, mid.first); split_x(L, L, dummy, mid.first - 1); merge(root, L, mid.second); merge(root, root, R); } } void solve() { for(int i = 0; i < n; i++) add(tin[i], tout[i], i, 0, q - 1, 0); root = nullptr; merge(root, root, new node(PT(0, 0))); merge(root, root, new node(PT(T, 0))); solve(0, q - 1, 0); for(int i = 0; i < q; i++) cout << answer[i] << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/geometry/kd-tree.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (int)1e5 + 42 + 17; const int MAXD = 5; inline int64_t sq(int x) { return x * 1ll * x; } struct point { int c[MAXD]; point() { } }; struct cmp { int current_d; cmp() { current_d = 0; } cmp(int d) { current_d = d; } bool operator() (const point& a, const point& b) { return a.c[current_d] < b.c[current_d]; } }; int64_t sq_dist(point a, point b, int d) { int64_t answer = 0; for(int i = 0; i < d; i++) answer += sq(a.c[i] - b.c[i]); return answer; } struct kd_tree { struct node { point p; int L, R, axis; node() { L = -1; R = -1; } node(point _p) { L = -1; R = -1; p = _p; } }; int psz = 0, D, root; node tr[MAXN << 2]; kd_tree() { D = 0; psz = 0; } kd_tree(int d) { D = d; psz = 0; } int new_node() { return psz++; } int build(point *from, point *to, int axis) { if(to - from == 0) return -1; point *mid = from + (to - from) / 2; nth_element(from, mid, to, cmp(axis)); int c_node = new_node(); tr[c_node] = node(*mid); tr[c_node].axis = axis; tr[c_node].L = build(from, mid, (axis + 1) % D); tr[c_node].R = build(mid + 1, to, (axis + 1) % D); return c_node; } void init(point *from, point *to, int d) { D = d; random_shuffle(from, to); root = build(from, to, 0); } void query(int idx, point q, int64_t &answer) { if(idx == -1) return; answer = min(answer, sq_dist(q, tr[idx].p, D)); if(tr[idx].p.c[tr[idx].axis] <= q.c[tr[idx].axis]) { query(tr[idx].R, q, answer); if(tr[idx].L != -1 && q.c[tr[idx].axis] - sqrt(answer) <= tr[idx].p.c[tr[idx].axis]) query(tr[idx].L, q, answer); } else { query(tr[idx].L, q, answer); if(tr[idx].R != -1 && q.c[tr[idx].axis] + sqrt(answer) >= tr[idx].p.c[tr[idx].axis]) query(tr[idx].R, q, answer); } } double nearest_neigbhor(point q) { int64_t answer = (1ll << 62ll); query(root, q, answer); return sqrt(answer); } }; int n, d; point li[MAXN]; void read() { cin >> n >> d; for(int i = 0; i < n; i++) for(int x = 0; x < d; x++) cin >> li[i].c[x]; } kd_tree t; void solve() { t.init(li, li + n, d); int q; cin >> q; for(int i = 0; i < q; i++) { point q; for(int x = 0; x < d; x++) cin >> q.c[x]; cout << setprecision(10) << fixed << t.nearest_neigbhor(q) << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/geometry/rectangle_union.cpp ================================================ #include #define endl '\n' #define int long long using namespace std; const int MAXN = (1 << 21); const int bound = (int)1e6 + 42; const int inf = (int)1e9 + 42; struct edge { int x, y1, y2, val; edge() {x = -1; y1 = -1; y2 = -1; val = -1;} edge(int _x, int _y1, int _y2, int _val) { x = _x; y1 = _y1; y2 = _y2; val = _val; } }; bool operator<(const edge &e1, const edge &e2) { return e1.x < e2.x; } int n; vector e; void read() { cin >> n; for(int i = 0; i < n; i++) { int mnx, mny, mxx, mxy; cin >> mnx >> mny >> mxx >> mxy; if(mxx < mnx) swap(mxx, mnx); if(mxy < mny) swap(mxy, mny); mnx--; mny--; e.push_back(edge(mnx, mny, mxy, 1)); e.push_back(edge(mxx, mny, mxy, -1)); } } int valy[MAXN]; vector comy; map id_y; int sz_y; void compress() { for(int i = 0; i < e.size(); i++) { comy.push_back(e[i].y1); comy.push_back(e[i].y2); } sort(comy.begin(), comy.end()); id_y[comy[0]] = 1; for(int i = 1; i < comy.size(); i++) if(comy[i] != comy[i - 1]) id_y[comy[i]] = id_y[comy[i - 1]] + 1ll; for(int i = 0; i < comy.size(); i++) valy[id_y[comy[i]]] = comy[i]; for(int i = 0; i < e.size(); i++) { e[i].y1 = id_y[e[i].y1]; e[i].y2 = id_y[e[i].y2]; } sz_y = id_y.size(); } struct segment_tree { struct node { int lazy, ans; node() {lazy = 0, ans = 0;} node(int v) { ans = v; lazy = 0;} }; node tr[4 * MAXN]; void update(int qL, int qR, int val, int l, int r, int idx) { if(qL <= l && r <= qR) { tr[idx].lazy += val; if(tr[idx].lazy == 0) tr[idx].ans = tr[2 * idx + 1].ans + tr[2 * idx + 2].ans; else tr[idx].ans = valy[r] - valy[l]; return; } if(qL > r || qR < l) return; if(l + 1 >= r) return; int mid = (l + r) >> 1; update(qL, qR, val, l, mid, 2 * idx + 1); update(qL, qR, val, mid, r, 2 * idx + 2); if(tr[idx].lazy == 0) tr[idx].ans = tr[2 * idx + 1].ans + tr[2 * idx + 2].ans; else tr[idx].ans = valy[r] - valy[l]; } }; segment_tree t; inline int mabs(int x) { return x < 0 ? -x : x; } int rectangle_union() { compress(); sort(e.begin(), e.end()); int ans = 0, last = -inf; for(int i = 0; i < e.size(); i++) { ans += mabs(e[i].x - last) * (long long)t.tr[0].ans; t.update(e[i].y1, e[i].y2, e[i].val, 1, sz_y, 0); last = e[i].x; } return ans; } void solve() { cout << rectangle_union() << endl; } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/dsu_bipartite.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); int n, m; pair e[MAXN]; void read() { cin >> n >> m; for(int i = 0; i < m; i++) cin >> e[i].first >> e[i].second; } int ds_sz[MAXN], col[MAXN], par[MAXN]; vector li[MAXN]; int root(int u) { if(u == par[u]) return u; return (par[u] = root(par[u])); } void unite(int u, int v) { if(root(u) == root(v)) { if(col[u] == col[v]) { cout << "NO" << endl; exit(0); } return; } if(li[root(u)].size() > li[root(v)].size()) swap(u, v); if(col[u] == col[v]) for(int ver: li[root(u)]) col[ver] ^= 1; for(int ver: li[root(u)]) li[root(v)].push_back(ver); par[root(u)] = root(v); } void solve() { for(int i = 1; i <= n; i++) ds_sz[i] = 1, col[i] = 1, li[i].push_back(i), par[i] = i; for(int i = 0; i < m; i++) unite(e[i].first, e[i].second); cout << "YES" << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/eulerian_path.cpp ================================================ #include using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } template ostream &operator<<(ostream &out, const pair &x) { return out << x.first << ' ' << x.second; } template istream &operator>>(istream &in, pair &x) { return in >> x.first >> x.second; } template istream &operator>>(istream &in, vector &a) { for(auto &x: a) { in >> x; } return in; }; template ostream &operator<<(ostream &out, vector &a) { for(auto &x: a) { out << x << ' '; } return out; }; /* https://codesprintla24.kattis.com/contests/codesprintla24open/problems/catbusplan Problem Statement: Split a graph into k edge-disjoint paths. Note that the Eulerian path algorithm works only when there are at most 2 odd degree vertices, as otherwise, when starting the DFS from a degree of odd degree, you might disconnect the graph (and the splicing of the cycles on the path doesn't work). To fix this, we add fake edges between all but one pair of vertices of odd degree, and then start the DFS from one of the 2 odd vertices that are left. */ int n, m, k; vector>> adj; vector> edges; void read() { cin >> n >> m >> k; adj.assign(n, {}); edges.resize(m); for(int i = 0; i < m; i++) { int u, v; cin >> u >> v; u--, v--; adj[u].push_back({v, i * 2}); adj[v].push_back({u, i * 2 + 1}); edges[i] = {u, v}; } } vector answer; vector used; vector po; vector deg; void dfs(int u) { for(; po[u] < (int)adj[u].size();) { int idx = po[u]++; if(!used[adj[u][idx].second >> 1]) { used[adj[u][idx].second >> 1] = true; dfs(adj[u][idx].first); answer.push_back(adj[u][idx].second); } } } pair get_edge(int edge_i) { if(edge_i & 1) { return edges[edge_i >> 1]; } else { return {edges[edge_i >> 1].second, edges[edge_i >> 1].first}; } } void dfs_visit_nodes(int u, vector &visited, vector &nodes) { nodes.push_back(u); visited[u] = true; for(auto [v, edge_i]: adj[u]) { if(!visited[v]) { dfs_visit_nodes(v, visited, nodes); } } } void solve() { if(k > m) { cout << "Impossible\n"; return; } used.assign(m, false); po.assign(n, 0); deg.assign(n, 0); vector used_vers(n, false); for(int i = 0; i < n; i++) { deg[i] = adj[i].size(); } int broken = m; vector> pre_paths; for(int u = 0; u < n; u++) { if(!used_vers[u]) { vector nodes_here; dfs_visit_nodes(u, used_vers, nodes_here); vector> broken_edges_here; int last_odd = -1; for(int i: nodes_here) { if(deg[i] % 2 == 1) { if(last_odd != -1) { broken_edges_here.push_back({last_odd, i}); last_odd = -1; } else { last_odd = i; } } } while((int)broken_edges_here.size() > 1) { auto [i, j] = broken_edges_here.back(); adj[i].push_back({j, 2 * broken}); adj[j].push_back({i, 2 * broken + 1}); broken++; used.push_back(false); edges.push_back({i, j}); deg[i]++; deg[j]++; broken_edges_here.pop_back(); } answer.clear(); if(!broken_edges_here.empty()) { dfs(broken_edges_here[0].first); } else { dfs(u); } pre_paths.push_back(answer); } } vector> paths; for(auto path: pre_paths) { vector new_path; for(int x: path) { if(x >= 2 * m) { if(!new_path.empty()) { paths.push_back(new_path); } new_path.clear(); } else { new_path.push_back(x); } } if(!new_path.empty()) { paths.push_back(new_path); } } if((int)paths.size() > k) { cout << "Impossible\n"; return; } int need = k - (int)paths.size(); for(int i = 0; i < (int)paths.size(); i++) { while((int)paths[i].size() > 1 && need > 0) { paths.push_back({paths[i].back()}); paths[i].pop_back(); need--; } } assert(need == 0); cout << "Possible\n"; for(auto &path: paths) { cout << get_edge(path[0]).first + 1 << ' '; for(auto edge_i: path) { cout << get_edge(edge_i).second + 1 << ' '; } cout << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int T = 1; // cin >> T; for(int test = 1; test <= T; test++) { read(); // cout << "Case #" << test << ": "; solve(); } return 0; } ================================================ FILE: old_impl/graph/max_anticlique.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (52); int G[MAXN][MAXN], n; int mn_deg, comp_size; bitset st; vector adj[MAXN]; bool visited[MAXN]; int get_deg(int u) { int res = 0; for(int v = 0; v < n; v++) if(st[v]) res += G[u][v]; return res; } void dfs(int u) { visited[u] = true; mn_deg = min(mn_deg, (int)adj[u].size()); comp_size++; for(int v: adj[u]) if(!visited[v]) dfs(v); } int brute() { for(int u = 0; u < n; u++) if(st[u]) visited[u] = false, adj[u].clear(); for(int u = 0; u < n; u++) if(st[u]) for(int v = 0; v < n; v++) if(G[u][v] && st[v]) adj[u].push_back(v); int res = 0; for(int u = 0; u < n; u++) if(st[u] && !visited[u]) { mn_deg = MAXN; comp_size = 0; dfs(u); if(mn_deg <= 1) res += ((comp_size + 1) / 2); else res += (comp_size / 2); } return res; } int rec() { if(!st.count()) return 0; int d = -1; for(int v = 0; v < n; v++) if(st[v] && (d == -1 || get_deg(v) > get_deg(d))) d = v; if(get_deg(d) <= 2) return brute(); int ret = 0; bitset prv = st; st[d] = 0; ret = max(ret, rec()); st = prv; st[d] = 0; for(int u = 0; u < n; u++) if(G[u][d]) st[u] = 0; ret = max(ret, 1 + rec()); st = prv; return ret; } /// O(1.38 ^ n) worst case int max_anticlique() { for(int i = 0; i < n; i++) st[i] = 1; return rec(); } void read() {} void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/maximum_closure.cpp ================================================ #include #define endl '\n' using namespace std; template inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; } template inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; } const int MAXN = (1 << 20); template struct max_flow { const static FlowT finf = 1e18 + 42 + 17; const static FlowT feps = 0; struct edge { FlowT flow, cap; int idx, rev, to; edge() { flow = 0; cap = 0; rev = 0; idx = 0; to = 0; } edge(int _to, int _rev, FlowT _flow, FlowT _cap, int _idx) { to = _to; rev = _rev; flow = _flow; cap = _cap; idx = _idx; } }; vector G[MAXN]; int n, dist[MAXN], po[MAXN]; bool bfs(int s, int t) { dist[s] = -1, po[s] = 0; dist[t] = -1, po[t] = 0; for(int v = 0; v <= n; v++) dist[v] = -1, po[v] = 0; queue Q; Q.push(s); dist[s] = 0; while(!Q.empty()) { int u = Q.front(); Q.pop(); for(edge e: G[u]) if(dist[e.to] == -1 && e.flow < e.cap) { dist[e.to] = dist[u] + 1; Q.push(e.to); } } return dist[t] != -1; } FlowT dfs(int u, int t, FlowT fl = finf) { if(u == t) return fl; for(; po[u] < G[u].size(); po[u]++) { auto &e = G[u][po[u]]; if(dist[e.to] == dist[u] + 1 && e.flow < e.cap) { FlowT f = dfs(e.to, t, min(fl, e.cap - e.flow)); e.flow += f; G[e.to][e.rev].flow -= f; if(f > 0) return f; } } return 0; } void init(int _n) { n = _n; for(int i = 0; i <= n; i++) G[i].clear(); } void add_edge(int u, int v, FlowT w, int idx = -1) { G[u].push_back(edge(v, G[v].size(), 0, w, idx)); G[v].push_back(edge(u, G[u].size() - 1, 0, 0, -1)); } FlowT flow(int s, int t) { if(s == t) return finf; FlowT ret = 0, to_add; while(bfs(s, t)) while((to_add = dfs(s, t))) ret += to_add; return ret; } }; template struct maximum_closure { int n; T w[MAXN]; max_flow mf; vector adj[MAXN]; void init(int _n) { n = _n; for(int i = 1; i <= n; i++) w[i] = 0, adj[i].clear(); } void add_clause(int i, int j) { adj[i].push_back(j); } int dfs_time, cnt_comp, comp[MAXN], disc[MAXN], low[MAXN]; bool in_stack[MAXN]; stack st; void dfs_tarjan(int u) { disc[u] = low[u] = ++dfs_time; in_stack[u] = 1; st.push(u); for(int v: adj[u]) if(disc[v] == -1) { dfs_tarjan(v); chkmin(low[u], low[v]); } else if(in_stack[v]) chkmin(low[u], disc[v]); if(low[u] == disc[u]) { cnt_comp++; while(st.top() != u) { in_stack[st.top()] = 0; comp[st.top()] = cnt_comp; st.pop(); } comp[u] = cnt_comp; in_stack[u] = 0; st.pop(); } } T solve() { for(int i = 1; i <= n; i++) disc[i] = -1; dfs_time = 0, cnt_comp = 0; for(int i = 1; i <= n; i++) if(disc[i] == -1) dfs_tarjan(i); int s = cnt_comp + 1, t = cnt_comp + 2; mf.init(cnt_comp + 3); vector new_w; new_w.assign(cnt_comp + 1, 0); for(int i = 1; i <= n; i++) new_w[comp[i]] += w[i]; for(int i = 1; i <= n; i++) for(int j: adj[i]) mf.add_edge(comp[i], comp[j], max_flow::finf); T sum = 0; for(int i = 1; i <= cnt_comp; i++) { if(new_w[i] < 0) mf.add_edge(s, i, -new_w[i]); else mf.add_edge(i, t, new_w[i]), sum += new_w[i]; } return sum - mf.flow(s, t); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/mincost_maxflow.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 10); const int inf = (int)1e9 + 42; int read_int(); struct edge { int to, rev, flow, cap, cost; edge() { to = 0; rev = 0; flow = 0; cap = 0; cost = 0; } edge(int _to, int _rev, int _flow, int _cap, int _cost) { to = _to; rev = _rev; flow = _flow; cap = _cap; cost = _cost; } }; int cnt_nodes = 0, s = MAXN - 1, t = MAXN - 2; vector G[MAXN]; void add_edge(int u, int v, int w, int cost) { edge t = edge(v, G[v].size(), 0, w, cost); edge r = edge(u, G[u].size(), 0, 0, -cost); G[u].push_back(t); G[v].push_back(r); } deque Q; bool is_inside[MAXN]; int dist[MAXN], par_idx[MAXN], par[MAXN]; bool spfa() { for(int i = 0; i <= cnt_nodes; i++) { dist[i] = inf; } dist[t] = inf; Q.clear(); dist[s] = 0; is_inside[s] = true; Q.push_back(s); while(!Q.empty()) { int u = Q.front(); is_inside[u] = false; Q.pop_front(); for(int i = 0; i < (int)G[u].size(); i++) { if(G[u][i].cap > G[u][i].flow && dist[u] + G[u][i].cost < dist[G[u][i].to]) { dist[G[u][i].to] = dist[u] + G[u][i].cost; par_idx[G[u][i].to] = i; par[G[u][i].to] = u; if(is_inside[G[u][i].to]) { continue; } if(!Q.empty() && dist[G[u][i].to] > dist[Q.front()]) { Q.push_back(G[u][i].to); } else { Q.push_front(G[u][i].to); } is_inside[G[u][i].to] = true; } } } return dist[t] != inf; } pair min_cost_flow(int flow) { int f = 0, ret = 0; while(f <= flow && spfa()) { int mn_flow = flow - f, u = t; while(u != s) { mn_flow = min(mn_flow, G[par[u]][par_idx[u]].cap - G[par[u]][par_idx[u]].flow); u = par[u]; } u = t; while(u != s) { G[par[u]][par_idx[u]].flow += mn_flow; G[u][G[par[u]][par_idx[u]].rev].flow -= mn_flow; ret += G[par[u]][par_idx[u]].cost * mn_flow; u = par[u]; } f += mn_flow; } return make_pair(f, ret); } void read() {} void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } const int maxl = 100000; char buff[maxl]; int ret_int, pos_buff = 0; void next_char() { if(++pos_buff == maxl) { fread(buff, 1, maxl, stdin), pos_buff = 0; } } int read_int() { ret_int = 0; for(; buff[pos_buff] < '0' || buff[pos_buff] > '9'; next_char()) ; for(; buff[pos_buff] >= '0' && buff[pos_buff] <= '9'; next_char()) { ret_int = ret_int * 10 + buff[pos_buff] - '0'; } return ret_int; } ================================================ FILE: old_impl/graph/persistent_dsu.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct persistent_dsu { struct state { int u, v, rnku, rnkv; state() {u = -1; v = -1; rnkv = -1; rnku = -1;} state(int _u, int _rnku, int _v, int _rnkv) { u = _u; rnku = _rnku; v = _v; rnkv = _rnkv; } }; stack st; int par[MAXN], depth[MAXN]; persistent_dsu() {memset(par, -1, sizeof(par)); memset(depth, 0, sizeof(depth));} int root(int x) { if(x == par[x]) return x; return root(par[x]); } void init(int n) { for(int i = 0; i <= n; i++) { par[i] = i; depth[i] = 1; } } bool connected(int x, int y) { return root(x) == root(y); } void unite(int x, int y) { int rx = root(x), ry = root(y); st.push(state(rx, depth[rx], ry, depth[ry])); if(depth[rx] < depth[ry]) par[rx] = ry; else if(depth[ry] < depth[rx]) par[ry] = rx; else { par[rx] = ry; depth[rx]++; } } void backtrack(int c) { while(!st.empty() && c) { par[st.top().u] = st.top().u; par[st.top().v] = st.top().v; depth[st.top().u] = st.top().rnku; depth[st.top().v] = st.top().rnkv; st.pop(); c--; } } }; void read() { } persistent_dsu d; void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/scc_tarjan.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); int n, m; vector G[MAXN]; void read() { cin >> n >> m; for(int i = 0; i < m; i++) { int u, v; cin >> u >> v; G[u].push_back(v); } } stack st; vector> scc; int low[MAXN], disc[MAXN], comp[MAXN]; int dfs_time; bool in_stack[MAXN]; void dfs(int u) { low[u] = dfs_time; disc[u] = dfs_time; dfs_time++; in_stack[u] = true; st.push(u); int sz = G[u].size(), v; for(int i = 0; i < sz; i++) { v = G[u][i]; if(disc[v] == -1) { dfs(v); low[u] = min(low[u], low[v]); } else if(in_stack[v] == true) low[u] = min(low[u], disc[v]); } if(low[u] == disc[u]) { scc.push_back(vector()); while(st.top() != u) { scc[scc.size() - 1].push_back(st.top()); in_stack[st.top()] = false; st.pop(); } scc[scc.size() - 1].push_back(u); in_stack[u] = false; st.pop(); } } void tarjan() { memset(comp, -1, sizeof(comp)); memset(disc, -1, sizeof(disc)); memset(low, -1, sizeof(low)); memset(in_stack, 0, sizeof(in_stack)); dfs_time = 0; while(!st.empty()) st.pop(); for(int i = 1; i <= n; i++) if(disc[i] == -1) dfs(i); int sz = scc.size(); for(int i = 0; i < sz; i++) for(int j = 0; j < (int)scc[i].size(); j++) comp[scc[i][j]] = i; } void solve() { tarjan(); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/graph/st_numbering.cpp ================================================ #include #define endl '\n' //#pragma GCC optimize ("O3") //#pragma GCC target ("sse4") using namespace std; template inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; } template inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; } const int MAXN = (1 << 20); int n, m, s, t; vector adj[MAXN]; void read() { cin >> n >> m >> s >> t; for(int i = 0; i < m; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } int low[MAXN], disc[MAXN], dfs_time = 0, par[MAXN], sign[MAXN]; vector preorder; bool tarjan_check(int u, int pr = -1) { low[u] = disc[u] = ++dfs_time; int child_cnt = 0; for(int v: adj[u]) if(v != pr) { if(disc[v] == -1) { child_cnt++; if(!tarjan_check(v, u)) return false; chkmin(low[u], low[v]); if(pr != -1 && low[v] >= disc[u]) return false; } else chkmin(low[u], disc[v]); } if(pr == -1 && child_cnt > 1) return false; return true; } void tarjan(int u, int pr = -1) { low[u] = disc[u] = ++dfs_time; for(int v: adj[u]) if(v != pr) { if(disc[v] == -1) { preorder.push_back(v); tarjan(v, u); chkmin(low[u], low[v]); par[v] = u; } else chkmin(low[u], disc[v]); } } list st_li; list::iterator it_ver[MAXN]; vector st_numbering() { /// additional edge adj[s].push_back(t); adj[t].push_back(s); dfs_time = 0; preorder.clear(); for(int i = 1; i <= n; i++) disc[i] = low[i] = -1, sign[i] = 0; if(!tarjan_check(t)) return vector(); /// no bipolar orientation for(int i = 1; i <= n; i++) if(disc[i] == -1) return vector(); /// no bipolar orientation for(int i = 1; i <= n; i++) disc[i] = low[i] = -1, sign[i] = 0; dfs_time = 0; preorder.clear(); disc[s] = low[s] = ++dfs_time; sign[disc[s]] = -1; tarjan(t); st_li.clear(); st_li.push_back(s); st_li.push_back(t); it_ver[disc[s]] = st_li.begin(); it_ver[disc[t]] = next(st_li.begin()); for(int v: preorder) { if(sign[low[v]] == -1) it_ver[disc[v]] = st_li.insert(it_ver[disc[par[v]]], v); else it_ver[disc[v]] = st_li.insert(next(it_ver[disc[par[v]]]), v); sign[disc[par[v]]] = -sign[low[v]]; } vector ret(st_li.begin(), st_li.end()); return ret; } void solve() { vector li = st_numbering(); for(int v: li) cout << v << " "; cout << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/combinatorics.cpp ================================================ #include using namespace std; const int mod = (int)1e9 + 7; template T pw(T a, int pw) { T ret(1); while(pw) { if(pw & 1) { ret *= a; } a *= a; pw >>= 1; } return ret; } template class modint_t { private: unsigned x; public: modint_t() { x = 0; } modint_t(unsigned _x) { x = _x; } operator unsigned() { return x; } bool operator==(const modint_t& m) const { return x == m.x; } bool operator!=(const modint_t& m) const { return x != m.x; } modint_t operator+=(const modint_t& m) { x = (x + m.x >= mod ? x + m.x - mod : x + m.x); return *this; } modint_t operator-=(const modint_t& m) { x = (x < m.x ? x - m.x + mod : x - m.x); return *this; } modint_t operator*=(const modint_t& m) { x = 1ULL * x * m.x % mod; return *this; } modint_t operator+=(const int32_t m) { x = (x + (m % mod) >= mod ? x + (m % mod) - mod : x + (m % mod)); return *this; } modint_t operator-=(const int32_t m) { x = (x < (m % mod) ? x - (m % mod) + mod : x - (m % mod)); return *this; } modint_t operator*=(const int32_t m) { x = 1ULL * x * (m % mod) % mod; return *this; } modint_t operator+=(const int64_t m) { x = (x + (m % mod) >= mod ? x + (m % mod) - mod : x + (m % mod)); return *this; } modint_t operator-=(const int64_t m) { x = (x < (m % mod) ? x - (m % mod) + mod : x - (m % mod)); return *this; } modint_t operator*=(const int64_t m) { x = 1ULL * x * (m % mod) % mod; return *this; } modint_t operator+(const modint_t& m) const { return modint_t(*this) += m; } modint_t operator-(const modint_t& m) const { return modint_t(*this) -= m; } modint_t operator*(const modint_t& m) const { return modint_t(*this) *= m; } modint_t operator+(const int32_t m) const { return modint_t(*this) += m; } modint_t operator-(const int32_t m) const { return modint_t(*this) -= m; } modint_t operator*(const int32_t m) const { return modint_t(*this) *= m; } modint_t operator+(const int64_t m) const { return modint_t(*this) += m; } modint_t operator-(const int64_t m) const { return modint_t(*this) -= m; } modint_t operator*(const int64_t m) const { return modint_t(*this) *= m; } modint_t inv() { return pw(modint_t(*this), mod - 2); } }; using mint = modint_t; vector fact, ifact, inv_prec; void precompute(int bound) { fact.resize(bound + 1); ifact.resize(bound + 1); inv_prec.resize(bound + 1); fact[0] = 1; for(int i = 1; i <= bound; i++) { fact[i] = fact[i - 1] * i; } ifact[bound] = fact[bound].inv(); for(int i = bound - 1; i >= 0; i--) { ifact[i] = ifact[i + 1] * (i + 1); } for(int i = 1; i <= bound; i++) { inv_prec[i] = fact[i - 1] * ifact[i]; } } mint C(int n, int k) { if(n < k || n < 0 || k < 0) { return 0; } return fact[n] * ifact[n - k] * ifact[k]; } int main() { precompute((int)1e6 + 42); return 0; } ================================================ FILE: old_impl/math/fft.cpp ================================================ #include #define endl '\n' using namespace std; const double PI = acos(-1); const int MAXN = (1 << 21); struct complex_base { double x, y; complex_base(double _x = 0, double _y = 0) { x = _x; y = _y; } friend complex_base operator-(const complex_base &a, const complex_base &b) { return complex_base(a.x - b.x, a.y - b.y); } friend complex_base operator+(const complex_base &a, const complex_base &b) { return complex_base(a.x + b.x, a.y + b.y); } friend complex_base operator*(const complex_base &a, const complex_base &b) { return complex_base(a.x * b.x - a.y * b.y, a.y * b.x + b.y * a.x); } friend void operator/=(complex_base &a, const double &P) { a.x /= P; a.y /= P; } }; int bit_rev[MAXN]; int last_n_fft = -1, ilast_n_fft = -1; complex_base root[MAXN], iroot[MAXN]; void fft(complex_base *a, int lg) { int n = (1 << lg); if(last_n_fft != n) { double ang = 2 * PI / n; for(int i = 0; i < (n >> 1); i++) root[i] = complex_base(cos(ang * i), sin(ang * i)); last_n_fft = n; } for(int i = 1; i < n; i++) { bit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1)); if(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]); } for(int len = 2; len <= n; len <<= 1) { int step = (n / len); for(int j = 0; j < (len >> 1); j++) for(int i = 0; i < n; i += len) { complex_base u = a[i + j], v = root[step * j] * a[i + j + (len >> 1)]; a[i + j] = u + v; a[i + j + (len >> 1)] = u - v; } } } void inv_fft(complex_base *a, int lg) { int n = (1 << lg); if(ilast_n_fft != n) { double ang = -2 * PI / n; for(int i = 0; i < (n >> 1); i++) iroot[i] = complex_base(cos(ang * i), sin(ang * i)); ilast_n_fft = n; } for(int i = 1; i < n; i++) { bit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1)); if(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]); } for(int len = 2; len <= n; len <<= 1) { int step = (n / len); for(int j = 0; j < (len >> 1); j++) for(int i = 0; i < n; i += len) { complex_base u = a[i + j], v = iroot[step * j] * a[i + j + (len >> 1)]; a[i + j] = u + v; a[i + j + (len >> 1)] = u - v; } } for(int i = 0; i < n; i++) a[i] /= n; } complex_base A[MAXN], B[MAXN]; vector mult(vector a, vector b) { if(a.size() * b.size() <= 256) { vector ans(a.size() + b.size(), 0); for(int i = 0; i < (int)a.size(); i++) for(int j = 0; j < (int)b.size(); j++) ans[i + j] += a[i] * b[j]; return ans; } int lg = 0; while((1 << lg) < (int)(a.size() + b.size())) ++lg; for(int i = 0; i < (1 << lg); i++) A[i] = B[i] = complex_base(0, 0); for(int i = 0; i < (int)a.size(); i++) A[i] = complex_base(a[i], 0); for(int i = 0; i < (int)b.size(); i++) B[i] = complex_base(b[i], 0); fft(A, lg); fft(B, lg); for(int i = 0; i < (1 << lg); i++) A[i] = A[i] * B[i]; inv_fft(A, lg); vector ans(a.size() + b.size(), 0); for(int i = 0; i < (int)ans.size(); i++) ans[i] = (int)(A[i].x + 0.5); return ans; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/fft_mod.cpp ================================================ #include #define endl '\n' using namespace std; template inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; } template inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; } const double PI = acos(-1); const int MAXN = (1 << 19); int mod; inline void addmod(int& x, int y, int mod) { (x += y) >= mod && (x -= mod); } inline int mulmod(int x, int y, int mod) { return x * 1ll * y % mod; } struct complex_base { double x, y; complex_base(double _x = 0, double _y = 0) { x = _x; y = _y; } friend complex_base operator-(const complex_base &a, const complex_base &b) { return complex_base(a.x - b.x, a.y - b.y); } friend complex_base operator+(const complex_base &a, const complex_base &b) { return complex_base(a.x + b.x, a.y + b.y); } friend complex_base operator*(const complex_base &a, const complex_base &b) { return complex_base(a.x * b.x - a.y * b.y, a.y * b.x + b.y * a.x); } friend void operator/=(complex_base &a, const double &P) { a.x /= P; a.y /= P; } }; int bit_rev[MAXN]; int last_n_fft = -1, ilast_n_fft = -1; complex_base root[MAXN], iroot[MAXN]; void fft(complex_base *a, int lg) { int n = (1 << lg); if(last_n_fft != n) { double ang = 2 * PI / n; for(int i = 0; i < (n >> 1); i++) root[i] = complex_base(cos(ang * i), sin(ang * i)); last_n_fft = n; } for(int i = 1; i < n; i++) { bit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1)); if(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]); } for(int len = 2; len <= n; len <<= 1) { int step = (n / len); for(int j = 0; j < (len >> 1); j++) for(int i = 0; i < n; i += len) { complex_base u = a[i + j], v = root[step * j] * a[i + j + (len >> 1)]; a[i + j] = u + v; a[i + j + (len >> 1)] = u - v; } } } void inv_fft(complex_base *a, int lg) { int n = (1 << lg); if(ilast_n_fft != n) { double ang = -2 * PI / n; for(int i = 0; i < (n >> 1); i++) iroot[i] = complex_base(cos(ang * i), sin(ang * i)); ilast_n_fft = n; } for(int i = 1; i < n; i++) { bit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1)); if(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]); } for(int len = 2; len <= n; len <<= 1) { int step = (n / len); for(int j = 0; j < (len >> 1); j++) for(int i = 0; i < n; i += len) { complex_base u = a[i + j], v = iroot[step * j] * a[i + j + (len >> 1)]; a[i + j] = u + v; a[i + j + (len >> 1)] = u - v; } } for(int i = 0; i < n; i++) a[i] /= n; } complex_base A[MAXN], B[MAXN]; vector mult(const vector &a, const vector &b) { if(a.size() * b.size() <= 128) { vector ans(a.size() + b.size(), 0); for(int i = 0; i < (int)a.size(); i++) for(int j = 0; j < (int)b.size(); j++) ans[i + j] = (ans[i + j] + a[i] * 1ll * b[j]) % mod; return ans; } int lg = 0; while((1 << lg) < (int)(a.size() + b.size())) ++lg; for(int i = 0; i < (1 << lg); i++) A[i] = B[i] = complex_base(0, 0); for(int i = 0; i < (int)a.size(); i++) A[i] = complex_base(a[i], 0); for(int i = 0; i < (int)b.size(); i++) B[i] = complex_base(b[i], 0); fft(A, lg); fft(B, lg); for(int i = 0; i < (1 << lg); i++) A[i] = A[i] * B[i]; inv_fft(A, lg); vector ans(a.size() + b.size(), 0); for(int i = 0; i < (int)ans.size(); i++) ans[i] = (int64_t)(A[i].x + 0.5) % mod; return ans; } vector mult_mod(const vector &a, const vector &b) { /// Thanks pavel.savchenkov // a = a0 + sqrt(MOD) * a1 // a = a0 + base * a1 int base = (int)sqrtl(mod); vector a0(a.size()), a1(a.size()); for(int i = 0; i < (int)a.size(); i++) { a0[i] = a[i] % base; a1[i] = a[i] / base; } vector b0(b.size()), b1(b.size()); for(int i = 0; i < (int)b.size(); i++) { b0[i] = b[i] % base; b1[i] = b[i] / base; } vector a01 = a0; for(int i = 0; i < (int)a.size(); i++) addmod(a01[i], a1[i], mod); vector b01 = b0; for(int i = 0; i < (int)b.size(); i++) addmod(b01[i], b1[i], mod); vector C = mult(a01, b01); // 1 vector a0b0 = mult(a0, b0); // 2 vector a1b1 = mult(a1, b1); // 3 vector mid = C; for(int i = 0; i < (int)mid.size(); i++) { addmod(mid[i], -a0b0[i] + mod, mod); addmod(mid[i], -a1b1[i] + mod, mod); } vector res = a0b0; for(int i = 0; i < (int)res.size(); i++) addmod(res[i], mulmod(base, mid[i], mod), mod); base = mulmod(base, base, mod); for(int i = 0; i < (int)res.size(); i++) addmod(res[i], mulmod(base, a1b1[i], mod), mod); return res; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/fft_xor.cpp ================================================ #include #define endl '\n' #define int long long using namespace std; const int MAXN = (1 << 20); typedef vector polynomial; void fft(polynomial &a, int low, int high) { if(low == high - 1) return; int len = (high - low) / 2, mid = low + len; fft(a, low, mid); fft(a, mid, high); for(int i = low; i < mid; i++) { int x1 = a[i]; int x2 = a[i + len]; a[i] = (x1 - x2); a[i + len] = (x1 + x2); } } void inv_fft(polynomial &a, int low, int high) { if(low == high - 1) return; int len = (high - low) / 2, mid = low + len; for(int i = low; i < mid; i++) { int y1 = a[i]; int y2 = a[i + len]; a[i] = (y1 + y2) / 2; a[i + len] = (y2 - y1) / 2; } inv_fft(a, low, mid); inv_fft(a, mid, high); } void read() { } void solve() { } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/fft_xor_mod.cpp ================================================ #include #define endl '\n' #define int long long #define pow mypow using namespace std; const int MAXN = (1 << 20); const int mod = (int)1e9 + 7; int INV2; typedef vector polynomial; int pow(int x, int p) { if(p == 0) return 1; if(p % 2 == 0) { int d = pow(x, p / 2); return (d * d) % mod; } return (pow(x, p - 1) * x) % mod; } int inv(int x, int mod) { return pow(x, mod - 2); } void fft(polynomial &a, int low, int high) { if(high == low + 1) return; int len = (high - low) >> 1, mid = low + len; fft(a, low, mid); fft(a, mid, high); for(int i = low; i < mid; i++) { int x1 = a[i] % mod; int x2 = a[i + len] % mod; a[i] = (x1 - x2 + mod) % mod; a[i + len] = (x1 + x2) % mod; } } void inv_fft(polynomial &a, int low, int high) { if(high == low + 1) return; int len = (high - low) >> 1, mid = low + len; for(int i = low; i < mid; i++) { int y1 = a[i] % mod; int y2 = a[i + len] % mod; a[i] = ((y1 + y2) * INV2) % mod; a[i + len] = ((y2 - y1 + mod) * INV2) % mod; } inv_fft(a, low, mid); inv_fft(a, mid, high); } void read() { } void solve() { INV2 = inv(2, mod); cout << INV2 << endl; } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/gauss_elimination_equations.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const double eps = 1e-9; vector gauss(vector> &a) { int n = a.size(), m = a[0].size() - 1; vector where(m, -1); for(int col = 0, row = 0; col < m && row < n; col++) { int sel = row; for(int i = row; i < n; i++) if(abs(a[i][col]) > abs(a[sel][col])) sel = i; if(abs(a[sel][col]) < eps) { where[col] = -1; continue; } for(int i = col; i <= m; i++) swap(a[sel][i], a[row][i]); where[col] = row; for(int i = 0; i < n; i++) if(i != row) { if(abs(a[i][col]) < eps) continue; double c = a[i][col] / a[row][col]; for(int j = 0; j <= m; j++) a[i][j] -= c * a[row][j]; } row++; } vector ans(m, 0); for(int i = 0; i < m; i++) if(where[i] != -1) ans[i] = a[where[i]][m] / a[where[i]][i]; for(int i = 0; i < n; i++) { double sum = a[i][m]; for(int j = 0; j < m; j++) sum -= ans[j] * a[i][j]; if(abs(sum) > eps) return vector(); } return ans; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/gauss_elimination_equations_mod.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int64_t mod = (int64_t)1e9 + 7; int64_t pow(int64_t base, int64_t p, int64_t MOD) { if(p == 0) return 1; if(p % 2 == 0) { int64_t d = pow(base, p / 2, MOD); return (d * d) % MOD; } return (pow(base, p - 1, MOD) * base) % MOD; } int64_t inv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); } vector gauss(vector> &a, int64_t MOD) { int n = a.size(), m = a[0].size() - 1; for(int i = 0; i < n; i++) for(int j = 0; j <= m; j++) a[i][j] = (a[i][j] % MOD + MOD) % MOD; vector where(m, -1); for(int col = 0, row = 0; col < m && row < n; col++) { int sel = row; for(int i = row; i < n; i++) if(a[i][col] > a[sel][col]) sel = i; if(a[sel][col] == 0) { where[col] = -1; continue; } for(int i = col; i <= m; i++) swap(a[sel][i], a[row][i]); where[col] = row; int64_t c_inv = inv(a[row][col], MOD); for(int i = 0; i < n; i++) if(i != row) { if(a[i][col] == 0) continue; int64_t c = (a[i][col] * c_inv) % MOD; for(int j = 0; j <= m; j++) a[i][j] = (a[i][j] - c * a[row][j] % MOD + MOD) % MOD; } row++; } vector ans(m, 0); for(int i = 0; i < m; i++) if(where[i] != -1) ans[i] = (a[where[i]][m] * inv(a[where[i]][i], MOD)) % MOD; for(int i = 0; i < n; i++) { int64_t sum = a[i][m] % MOD; for(int j = 0; j < m; j++) sum = (sum + MOD - (ans[j] * a[i][j]) % MOD) % MOD; if(sum != 0) return vector(); } return ans; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/gauss_elimination_equations_mod_number_solutions.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int64_t mod = (int64_t)1e9 + 7; int64_t pow(int64_t base, int64_t p, int64_t MOD) { if(p == 0) return 1; if(p % 2 == 0) { int64_t d = pow(base, p / 2, MOD); return (d * d) % MOD; } return (pow(base, p - 1, MOD) * base) % MOD; } int64_t inv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); } int64_t gauss(vector> &a, int64_t MOD) { int n = a.size(), m = a[0].size() - 1; for(int i = 0; i < n; i++) for(int j = 0; j <= m; j++) a[i][j] = (a[i][j] % MOD + MOD) % MOD; vector where(m, -1); for(int col = 0, row = 0; col < m && row < n; col++) { int sel = row; for(int i = row; i < n; i++) if(a[i][col] > a[sel][col]) sel = i; if(a[sel][col] == 0) { where[col] = -1; continue; } for(int i = col; i <= m; i++) swap(a[sel][i], a[row][i]); where[col] = row; int64_t c_inv = inv(a[row][col], MOD); for(int i = 0; i < n; i++) if(i != row) { if(a[i][col] == 0) continue; int64_t c = (a[i][col] * c_inv) % MOD; for(int j = 0; j <= m; j++) a[i][j] = (a[i][j] - c * a[row][j] % MOD + MOD) % MOD; } row++; } vector ans(m, 0); int64_t result = 1; for(int i = 0; i < m; i++) if(where[i] != -1) ans[i] = (a[where[i]][m] * inv(a[where[i]][i], MOD)) % MOD; else result = (result * MOD) % mod; for(int i = 0; i < n; i++) { int64_t sum = a[i][m] % MOD; for(int j = 0; j < m; j++) sum = (sum + MOD - (ans[j] * a[i][j]) % MOD) % MOD; if(sum != 0) return 0; } return result; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/matrix_exponential.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int mod = (int)1e9 + 7; const int64_t inf = (int64_t)1e16 + 42; template struct matrix { int n; vector > t; matrix(int _n, T val) {n = _n; t.assign(n, vector(n, val)); } matrix(int _n) {n = _n; t.assign(n, vector(n, 0)); } matrix() { n = 0; t.clear(); } matrix operator * (matrix b) { matrix c = matrix(n, 0); for(int i = 0; i < n; i++) for(int k = 0; k < n; k++) for(int j = 0; j < n; j++) c.t[i][j] = (c.t[i][j] + t[i][k] * b.t[k][j]) % mod; return c; } vector operator * (vector b) { vector c = vector(n, 0); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) c[i] = (c[i] + t[i][j] * b[j]) % mod; return c; } matrix operator ^ (matrix b) { matrix c = matrix(n, inf); for(int i = 0; i < n; i++) for(int k = 0; k < n; k++) for(int j = 0; j < n; j++) c.t[i][j] = min(c.t[i][j], t[i][k] + b.t[k][j]); return c; } matrix operator + (matrix b) { matrix c = matrix(n); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) c.t[i][j] = (t[i][j] + b.t[i][j]) % mod; return c; } matrix operator - (matrix b) { matrix c = matrix(n); for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) c.t[i][j] = (t[i][j] - b.t[i][j] + mod) % mod; return c; } matrix operator & (matrix b) { matrix c = matrix(n, -inf); for(int i = 0; i < n; i++) for(int k = 0; k < n; k++) for(int j = 0; j < n; j++) c.t[i][j] = max(c.t[i][j], t[i][k] + b.t[k][j]); return c; } }; template matrix pow_min(matrix base, int64_t p) { if(p == 1) return base; if(p % 2ll == 0ll) { matrix d = pow_min(base, p / 2ll); return d ^ d; } return base ^ pow_min(base, p - 1); } template matrix pow_max(matrix base, int64_t p) { if(p == 1) return base; if(p % 2ll == 0ll) { matrix d = pow_max(base, p / 2ll); return d & d; } return base & pow_max(base, p - 1); } template matrix pow(matrix base, int64_t p) { if(p == 1) return base; if(p % 2ll == 0ll) { matrix d = pow(base, p / 2ll); return d * d; } return base * pow(base, p - 1); } template void print(matrix mat) { for(int i = 0; i < mat.n; i++) for(int j = 0; j < mat.n; j++) if(mat.t[i][j] < inf) cout << mat.t[i][j] << " \n"[j == mat.n - 1]; else cout << "inf" << " \n"[j == mat.n - 1]; cout << endl; } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/math/number_theory.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int bound = 1000000; const int64_t mod = (int64_t)1e9 + 7; int64_t pow(int64_t x, int64_t p, int64_t MOD) { if(p == 0) return 1; if(p % 2 == 1) return (x * pow(x, p - 1, MOD)) % MOD; int64_t half = pow(x, p / 2, MOD); return (half * half) % MOD; } int lp[bound + 1], phi[bound + 1]; vector pr; template vector get_divs(T x) { if(x <= bound) { vector ret; while(x != 1) { ret.push_back(lp[x]); x /= lp[x]; } return ret; } vector ret; for(T d = 2; d * 1ll * d <= x; d++) while(x % d == 0) ret.push_back(d), x /= d; if(x != 1) ret.push_back(x); return ret; } int64_t gcd(int64_t a, int64_t b, int64_t &x, int64_t &y) { if(a == 0) { x = 0; y = 1; return b; } int64_t x1, y1, g = gcd(b % a, a, x1, y1); x = y1 - (b / a) * x1; y = x1; return g; } void prepare() { phi[1] = 1; for(int i = 2; i <= bound; i++) { if(lp[i] == 0) lp[i] = i, phi[i] = i - 1, pr.push_back(i); else if(lp[i] == lp[i / lp[i]]) phi[i] = phi[i / lp[i]] * lp[i]; else phi[i] = phi[i / lp[i]] * (lp[i] - 1); for(int j = 0; j < pr.size() && i * 1ll * pr[j] <= bound && pr[j] <= lp[i]; j++) lp[i * pr[j]] = pr[j]; } } int64_t gcd(int64_t a, int64_t b) { if(a == 0 || b == 0) return a + b; return __gcd(a, b); } int64_t get_phi(int64_t x) { int64_t cop = x, ret = x; for(int64_t div = 2; div * div <= cop; div++) if(cop % div == 0) { while(cop % div == 0) cop /= div; ret /= div; ret *= (div - 1); } if(cop != 1) ret /= cop, ret *= (cop - 1); return ret; } int64_t pinv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); } int64_t inv(int64_t x, int64_t MOD) { if(gcd(x, MOD) != 1) return -1; if(MOD <= bound) return pow(x, phi[MOD] - 1, MOD); return pow(x, get_phi(MOD) - 1, MOD); } void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/aho_corasick.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct aho_corasick { int is_end[MAXN], link[MAXN], psz; map to[MAXN]; void clear() { for(int i = 0; i < psz; i++) is_end[i] = 0, link[i] = 0, to[i].clear(); psz = 1; is_end[0] = 1; } aho_corasick() { psz = MAXN - 2; clear(); } void add_word(string s) { int u = 0; for(char c: s) { if(!to[u].count(c)) to[u][c] = psz++; u = to[u][c]; } is_end[u] = 1; } void push_links() { queue Q; int u, v, j; char c; Q.push(0); link[0] = -1; while(!Q.empty()) { u = Q.front(); Q.pop(); for(auto it: to[u]) { v = it.second; c = it.first; j = link[u]; while(j != -1 && !to[j].count(c)) j = link[j]; if(j != -1) link[v] = to[j][c]; else link[v] = 0; Q.push(v); } } } }; int n, m; string s[MAXN]; void read() { cin >> n >> m; for(int i = 0; i < m; i++) cin >> s[i]; } aho_corasick aho; void solve() { aho.clear(); for(int i = 0; i < m; i++) aho.add_word(s[i]); aho.push_links(); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/aho_corasick_dynamic.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct aho_corasick_static { int cnt[MAXN], len[MAXN], link[MAXN], psz; map to[MAXN]; void clear() { for(int i = 0; i < psz; i++) cnt[i] = 0, len[i] = 0, link[i] = -1, to[i].clear(); psz = 1; link[0] = -1; cnt[0] = 0; } aho_corasick_static() { psz = MAXN - 2; clear(); } void add_word(string s) { int u = 0; for(char c: s) { if(!to[u].count(c)) to[u][c] = psz++, len[psz - 1] = len[u] + 1; u = to[u][c]; } cnt[u]++; } void push_links() { queue Q; int u, v, j; char c; Q.push(0); link[0] = -1; while(!Q.empty()) { u = Q.front(); Q.pop(); for(auto it: to[u]) { v = it.second; c = it.first; j = link[u]; while(j != -1 && !to[j].count(c)) j = link[j]; if(j != -1) link[v] = to[j][c]; else link[v] = 0; cnt[v] += cnt[link[v]]; Q.push(v); } } } int count(string p) { int u = 0, ans = 0; for(char c: p) { while(u != -1 && !to[u].count(c)) u = link[u]; if(u == -1) u = 0; else u = to[u][c]; ans += cnt[u]; } return ans; } }; struct aho_corasick { vector li[20]; aho_corasick_static ac[20]; void clear() { for(int i = 0; i < 20; i++) { li[i].clear(); ac[i].clear(); } } aho_corasick() { clear(); } void add_word(string s) { int pos = 0; for(int l = 0; l < 20; l++) if(li[l].empty()) { pos = l; break; } li[pos].push_back(s); ac[pos].add_word(s); for(int bef = 0; bef < pos; bef++) { ac[bef].clear(); for(string s2: li[bef]) { li[pos].push_back(s2); ac[pos].add_word(s2); } li[bef].clear(); } ac[pos].push_links(); } int count(string s) { int ans = 0; for(int l = 0; l < 20; l++) ans += ac[l].count(s); return ans; } }; int m; string s[MAXN]; void read() { cin >> m; for(int i= 0; i < m; i++) cin >> s[i]; } aho_corasick aho; void solve() { aho.clear(); for(int i = 0; i < m; i++) { aho.add_word(s[i]); cout << aho.count("aaaaaasssaaa") << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/kmp.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); string str, pat; void read() { cin >> str; cin >> pat; } vector failure_function(string p) { int sz = p.size(); vector f; f.assign(sz + 1, 0); int j = 0; f[0] = 0; for(int i = 1; i < sz; i++) { while(j >= 0 && p[i] != p[j]) { if(j >= 1) { j = f[j - 1]; } else { j = -1; } } j++; f[i] = j; } return f; } void match(vector f, string p, string s) { int psz = p.size(), sz = s.size(); int j = 0; for(int i = 0; i < sz; i++) { while(j >= 0 && p[j] != s[i]) { if(j >= 1) { j = f[j - 1]; } else { j = -1; } } j++; if(j == psz) { j = f[j - 1]; cout << "Found pattern in [" << i - psz + 1 << "; " << i << "]" << endl; } } } vector f; void solve() { f = failure_function(pat); match(f, pat, str); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/palindromic_tree.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct palindromic_tree { int s[MAXN], len[MAXN], link[MAXN]; map to[MAXN]; int n, last, psz; void clear() { s[n++] = -1; link[0] = 1; len[1] = -1; psz = 2; } int get_link(int v) { while(s[n - len[v] - 2] != s[n - 1]) v = link[v]; return v; } void add_letter(char c) { s[n++] = c; last = get_link(last); if(!to[last][c]) { len[psz] = len[last] + 2; link[psz] = to[get_link(link[last])][c]; to[last][c] = psz++; } last = to[last][c]; } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/rabin_karp.cpp ================================================ #include #define endl '\n' #define int long long using namespace std; const int MAXN = (1 << 20); struct rabin_karp { int mod, base, sz, len; int h[MAXN], base_pow[MAXN]; void init(string s, int _base, int _mod) { mod = _mod; base = _base; sz = s.size(); h[0] = 0; for(int i = 1; i <= sz; i++) h[i] = (h[i - 1] * base + s[i - 1]) % mod; base_pow[0] = 1; for(int i = 1; i <= sz; i++) base_pow[i] = (base_pow[i - 1] * base) % mod; } int get_hash(int l, int r) { len = r - l + 1; return (h[r] - (h[l - 1] * base_pow[len]) % mod + mod) % mod; } }; void read() { } void solve() { } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/suffix_array.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (int)1e5 + 42; const int MAXLOG = 20; struct suffix_array { pair, int> L[MAXN]; int P[MAXLOG + 1][MAXN], n, stp, cnt, sa[MAXN]; suffix_array() { n = 0; stp = 0; cnt = 0; } suffix_array(const string &s) : n(s.size()) { for(int i = 0; i < n; i++) { P[0][i] = s[i]; } sa[0] = 0; for(stp = 1, cnt = 1; cnt < n; stp++, cnt <<= 1) { for(int i = 0; i < n; i++) { L[i] = { {P[stp - 1][i], i + cnt < n ? P[stp - 1][i + cnt] : -1}, i }; } sort(L, L + n); for(int i = 0; i < n; i++) { P[stp][L[i].second] = i > 0 && L[i].first == L[i - 1].first ? P[stp][L[i - 1].second] : i; } } for(int i = 0; i < n; i++) { sa[i] = L[i].second; } } int &operator[](int idx) { return sa[idx]; } int lcp(int x, int y) { int k, ret = 0; if(x == y) { return n - x; } for(k = stp - 1; k >= 0 && x < n && y < n; k--) { if(P[k][x] == P[k][y]) { x += (1 << k), y += (1 << k), ret += (1 << k); } } return ret; } }; string s; void read() { cin >> s; } void solve() { suffix_array sa(s); for(int idx = 0; idx < (int)s.size(); idx++) { cout << sa[idx] << endl; } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/suffix_array_hash.cpp ================================================ #include #define endl '\n' #define int long long using namespace std; const int MAXN = (1 << 20); struct rabin_karp { int mod, base, sz; vector h, base_pow; void init(string s, int _mod, int _base) { mod = _mod; base = _base; sz = s.size(); h.assign(sz + 1, 0); base_pow.assign(sz + 1, 0); for(int i = 1; i <= sz; i++) h[i] = (h[i - 1] * base + s[i - 1]) % mod; base_pow[0] = 1; for(int i = 1; i <= sz; i++) base_pow[i] = (base_pow[i - 1] * base) % mod; } int get_hash(int l, int r) { int len = r - l + 1; return (h[r] - (h[l - 1] * base_pow[len]) % mod + mod) % mod; } }; rabin_karp fir, sec; string str; int sz; bool cmp(int i, int j) { int l = 1, r = min(sz - i, sz - j), mid, ans = 0; while(l <= r) { mid = (l + r) >> 1; if(fir.get_hash(i + 1, i + mid) == fir.get_hash(j + 1, j + mid) && sec.get_hash(i + 1, i + mid) == sec.get_hash(j + 1, j + mid)) { l = mid + 1; ans = mid; } else r = mid - 1; } if(ans == min(sz - i, sz - j)) return (sz - i) < (sz - j); return (str[i + ans] < str[j + ans]); } vector kasai(string s, vector sa) { sz = s.size(); vector lcp, pos; lcp.assign(sz, 0); pos.assign(sz, 0); for(int i = 0; i < sz; i++) pos[sa[i]] = i; int k = 0; for(int i = 0; i < sz; i++, k ? k-- : 0) { if(pos[i] == sz - 1) { k = 0; continue; } int j = sa[pos[i] + 1]; while(i + k < sz && j + k < sz && s[i + k] == s[j + k]) k++; lcp[pos[i]] = k; } return lcp; } vector build(string s) { vector _sa; sz = s.size(); str = s; fir.init(str, (int)(1e9 + 7), 131); sec.init(str, (int)(1e9 + 9), 137); _sa.assign(sz, 0); for(int i = 0; i < sz; i++) _sa[i] = i; stable_sort(_sa.begin(), _sa.end(), cmp); return _sa; } int n; string a; void read() { cin >> a; n = a.size(); } vector sa, lcp; void solve() { sa = build(a); lcp = kasai(a, sa); cout << "arr: "; for(int i = 0; i < n; i++) cout << sa[i] << " "; cout << endl; cout << "lcp: "; for(int i = 0; i < n - 1; i++) cout << lcp[i] << " "; cout << endl; } #undef int int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/suffix_array_log2.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); int n; string s; void read() { cin >> s; n = s.size(); } int lcp[MAXN], sa[MAXN], rnk[MAXN], idx[MAXN], temp[MAXN], gap; bool cmp(int i, int j) { if(idx[i] != idx[j]) return idx[i] < idx[j]; i += gap; j += gap; return (i < n && j < n) ? idx[i] < idx[j] : i > j; } void build_suffix_array() { for(int i = 0; i < n; i++) { sa[i] = i; idx[i] = s[i]; } for(gap = 1; ; gap = gap * 2) { sort(sa, sa + n, cmp); for(int i = 0; i < n - 1; i++) { temp[i + 1] = temp[i]; temp[i + 1] += cmp(sa[i], sa[i + 1]); } for(int i = 0; i < n; i++) idx[sa[i]] = temp[i]; if(temp[n - 1] == n - 1) break; } } void build_lcp() { int k = 0; for(int i = 0; i < n; i++) rnk[sa[i]] = i; for(int i = 0; i < n; i++, k ? k-- : 0) { if(rnk[i] == n - 1) { k = 0; continue; } int j = sa[rnk[i] + 1]; while(i + k < n && j + k < n && s[i + k] == s[j + k]) k++; lcp[rnk[i]] = k; } } int dp[MAXN][20]; int logr[MAXN]; void sparse_table() { for(int i = 0; i < n; i++) dp[i][0] = lcp[i]; for(int lg = 1; (1 << lg) <= n; lg++) for(int i = 0; i + (1 << lg) < n; i++) dp[i][lg] = min(dp[i][lg - 1], dp[i + (1 << (lg - 1))][lg - 1]); logr[0] = -1; for(int i = 1; i <= n; i++) logr[i] = logr[i / 2] + 1; } int LCP(int l, int r) { if(l > r) return n - sa[l]; int len = r - l + 1, lg = logr[len]; return min(dp[l][lg], dp[r - (1 << lg) + 1][lg]); } void prepare() { build_suffix_array(); build_lcp(); sparse_table(); } void solve() { prepare(); } int main() { read(); solve(); return 0; } ================================================ FILE: old_impl/strings/suffix_automaton.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct suffix_automaton { map to[MAXN]; int len[MAXN], link[MAXN]; int last, psz = 0; void add_letter(char c) { int p = last, cl, q; if(to[p].count(c)) { q = to[p][c]; if(len[q] == len[p] + 1) { last = q; return; } cl = psz++; len[cl] = len[p] + 1; to[cl] = to[q]; link[cl] = link[q]; link[q] = cl; last = cl; for(; to[p][c] == q; p = link[p]) { to[p][c] = cl; } return; } last = psz++; len[last] = len[p] + 1; for(; to[p][c] == 0; p = link[p]) { to[p][c] = last; } if(to[p][c] == last) { link[last] = p; return; } q = to[p][c]; if(len[q] == len[p] + 1) { link[last] = q; return; } cl = psz++; len[cl] = len[p] + 1; to[cl] = to[q]; link[cl] = link[q]; link[q] = cl; link[last] = cl; for(; to[p][c] == q; p = link[p]) { to[p][c] = cl; } } void clear() { for(int i = 0; i < psz; i++) { len[i] = 0, link[i] = 0, to[i].clear(); } psz = 1; last = 0; } void init(string s) { clear(); for(int i = 0; i < (int)s.size(); i++) { add_letter(s[i]); } } suffix_automaton() { psz = 0; clear(); } }; void read() {} suffix_automaton sa; void solve() { sa.clear(); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/strings/trie.cpp ================================================ #include using namespace std; struct trie { vector cnt, len; vector> to; trie() { clear(); } void clear() { cnt.assign(1, 0); len.assign(1, 0); to.assign(1, map()); } void add(string s) { int u = 0; for(char c: s) { if(!to[u].count(c)) { to[u][c] = len.size(); len.push_back(len[u] + 1); cnt.push_back(0); to.push_back(map()); } u = to[u][c]; cnt[u]++; } } void del(string s) { int u = 0; for(char c: s) { if(!to[u].count(c)) { return; } u = to[u][c]; cnt[u]--; } } int count(string s) { int u = 0; for(char c: s) { if(!to[u].count(c)) { return 0; } u = to[u][c]; } return cnt[u]; } }; trie t; void read() {} void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/centroid_decomposition.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); int n; vector adj[MAXN]; void read() { cin >> n; for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } int tr_sz[MAXN], cnt_vers; bool used[MAXN]; void pre_dfs(int u, int pr) { cnt_vers++; tr_sz[u] = 1; for(int v: adj[u]) { if(!used[v] && v != pr) { pre_dfs(v, u); tr_sz[u] += tr_sz[v]; } } } int centroid(int u, int pr) { for(int v: adj[u]) { if(!used[v] && v != pr && tr_sz[v] > cnt_vers / 2) { return centroid(v, u); } } return u; } int link[MAXN]; void decompose(int u, int pr = -1) { cnt_vers = 0; pre_dfs(u, u); int cen = centroid(u, u); link[cen] = pr; used[cen] = true; for(int v: adj[cen]) { if(!used[v]) { decompose(v, cen); } } used[cen] = false; } void solve() {} int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/dsu_on_tree.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); int n; vector G[MAXN]; void read() { cin >> n; for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; G[u].push_back(v); G[v].push_back(u); } } int tr_sz[MAXN]; void pre_dfs(int u, int pr) { tr_sz[u] = 1; for(int v: G[u]) { if(v != pr) { pre_dfs(v, u); tr_sz[u] += tr_sz[v]; } } } void add_vertex(int u) {} void clear(int u, int pr) {} void add(int u, int pr) { add_vertex(u); for(int v: G[u]) { if(v != pr) { add(v, u); } } } void dfs(int u, int pr, int keep) { pair mx = {-1, -1}; for(int v: G[u]) { if(v != pr) { mx = max(mx, {tr_sz[v], v}); } } for(int v: G[u]) { if(v != pr && v != mx.second) { dfs(v, u, 0); } } if(mx.second != -1) { dfs(mx.second, u, 1); } for(int v: G[u]) { if(v != pr && v != mx.second) { add(v, u); } } add_vertex(u); if(keep) { return; } clear(u, pr); } void solve() { pre_dfs(1, -1); dfs(1, -1, 1); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/hld.cpp ================================================ #include using namespace std; template inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; } template inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; } const int MAXN = (1 << 20); int n; vector adj[MAXN]; void read() { cin >> n; for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } int tr_sz[MAXN]; int pre_dfs(int u, int pr) { tr_sz[u] = 1; for(int v: adj[u]) if(v != pr) tr_sz[u] += pre_dfs(v, u); return tr_sz[u]; } int head[MAXN], par[MAXN][20], st[MAXN], en[MAXN], dfs_time; void decompose(int u, int pr, int head) { ::head[u] = head; st[u] = ++dfs_time; par[u][0] = pr; for(int i = 1; i < 20; i++) par[u][i] = par[par[u][i - 1]][i - 1]; int mx_sz = -1, f_c = -1; for(int v: adj[u]) if(v != pr) if(chkmax(mx_sz, tr_sz[v])) f_c = v; if(f_c != -1) decompose(f_c, u, head); for(int v: adj[u]) if(v != pr && v != f_c) decompose(v, u, v); en[u] = dfs_time; } inline int upper(int u, int v) { return st[u] <= st[v] && en[v] <= en[u]; } int lca(int u, int v) { if(upper(u, v)) return u; if(upper(v, u)) return v; for(int i = 19; i >= 0; i--) if(!upper(par[u][i], v)) u = par[u][i]; return par[u][0]; } void hld_precompute(int root) { pre_dfs(root, root); decompose(1, 1, 1); } vector > get_path_up(int u, int anc) { vector > ret; while(st[anc] < st[u]) { ret.push_back({max(st[anc] + 1, st[head[u]]), st[u]}); u = par[head[u]][0]; } return ret; } vector > get_path(int u, int v) { int l = lca(u, v); vector > ret = get_path_up(u, l); // if we consider vertices, not edges // ret.push_back({st[l], st[l]}); vector > oth = get_path_up(v, l); reverse(oth.begin(), oth.end()); // if the path is directed // for(auto &it: oth) swap(it.first, it.second); for(auto it: oth) ret.push_back(it); return ret; } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/lca-seg3.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int MAXLOG = 20; int n, w[MAXN]; vector adj[MAXN]; void read() { cin >> n; for(int i = 1; i <= n; i++) cin >> w[i]; for(int i = 1; i <= n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } int st[MAXN], en[MAXN], dfs_time, par[MAXN][MAXLOG], par_mn[MAXN][MAXLOG]; void pre_dfs(int u, int pr) { par[u][0] = pr; par_mn[u][0] = w[u]; st[u] = ++dfs_time; for(int i = 1; i < MAXLOG; i++) { par[u][i] = par[par[u][i - 1]][i - 1]; par_mn[u][i] = min(par_mn[u][i - 1], par_mn[par_mn[u][i - 1]][i - 1]); } for(int v: adj[u]) if(v != pr) pre_dfs(v, u); en[u] = dfs_time; } inline bool upper(int u, int v) { return st[u] <= st[v] && en[v] <= en[u]; } int lca(int u, int v) { if(upper(u, v)) return u; if(upper(v, u)) return v; for(int l = MAXLOG - 1; l >= 0; l--) if(!upper(par[u][l], v)) u = par[u][l]; return par[u][0]; } int get_path_up(int u, int anc) { if(upper(u, anc)) return (int)1e9; int ans = INT_MAX; for(int l = MAXLOG - 1; l >= 0; l--) if(!upper(par[u][l], anc)) { ans = min(ans, par_mn[u][l]); u = par[u][l]; } return ans; } int get_path(int u, int v) { int anc = lca(u, v), ans = w[anc]; ans = min(get_path_up(u, anc), get_path_up(v, anc)); return ans; } void lca_precompute(int root) { dfs_time = 0; pre_dfs(root, root); } void solve() { lca_precompute(1); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/link_cut_tree.cpp ================================================ #include using namespace std; const int MAXN = (1 << 20); random_device rd; mt19937_64 mt(rd()); struct node { int sz, prior, id, rev; node *par, *pp, *l, *r; node() { id = 0; sz = 0; rev = 0; prior = 0; par = nullptr; l = nullptr; r = nullptr; pp = nullptr; } node(int v) { id = v; sz = 1; rev = 0; prior = mt(); l = nullptr; r = nullptr; par = nullptr; pp = nullptr; } }; int size(node *v) { return v ? v->sz : 0; } void push(node *&t) { if(!t) { return; } if(t->rev) { swap(t->l, t->r); if(t->l) { t->l->rev ^= 1; } if(t->r) { t->r->rev ^= 1; } t->rev = 0; } } void pull(node *&v) { if(!v) { return; } push(v->l); push(v->r); v->par = nullptr; v->sz = size(v->l) + size(v->r) + 1; if(v->l) { v->l->par = v; } if(v->r) { v->r->par = v; } if(v->l && v->l->pp) { v->pp = v->l->pp, v->l->pp = nullptr; } if(v->r && v->r->pp) { v->pp = v->r->pp, v->r->pp = nullptr; } } void merge(node *&t, node *l, node *r) { push(l), push(r); if(!l) { t = r; return; } if(!r) { t = l; return; } if(l->prior > r->prior) { merge(l->r, l->r, r), t = l; } else { merge(r->l, l, r->l), t = r; } pull(t); } void split(node *t, node *&l, node *&r, int k, int add = 0) { push(t); if(!t) { l = nullptr; r = nullptr; return; } int idx = add + size(t->l); if(idx <= k) { split(t->r, t->r, r, k, idx + 1), l = t; } else { split(t->l, l, t->l, k, add), r = t; } pull(t); } node *get_root(node *t) { if(!t) { return nullptr; } while(t->par) { t = t->par; } return t; } node *remove_right(node *t) { node *rt = t; int pos = size(rt->l); if(rt->rev) { pos = size(rt) - pos - 1; } while(rt->par) { if(rt->par->r == rt) { pos += size(rt->par->l) + 1; } if(rt->par->rev) { pos = size(rt->par) - pos - 1; } rt = rt->par; } node *l, *r, *pp = rt->pp; rt->pp = nullptr; split(rt, l, r, pos); l->pp = pp; if(r) { r->pp = t; } return l; } node *remove_left(node *t) { node *rt = t; int pos = size(rt->l); if(rt->rev) { pos = size(rt) - pos - 1; } while(rt->par) { if(rt->par->r == rt) { pos += size(rt->par->l) + 1; } if(rt->par->rev) { pos = size(rt->par) - pos - 1; } rt = rt->par; } node *l, *r, *pp = rt->pp; rt->pp = nullptr; split(rt, l, r, pos - 1); l->pp = pp; return r; } node *merge_trees(node *u, node *t) { u = get_root(u); t = get_root(t); t->pp = nullptr; merge(u, u, t); return u; } struct link_cut_tree { node *ver[MAXN]; node *access(node *t) { t = remove_right(t); while(t->pp) { node *u = t->pp; u = remove_right(u); t = merge_trees(u, t); } return t; } node *find_root(node *u) { u = access(u); push(u); while(u->l) { u = u->l, push(u); } access(u); return u; } void make_root(node *u) { u = access(u); u->rev ^= 1; push(u); } void link(node *u, node *w) { make_root(u); access(w); merge_trees(w, u); } void cut(node *p) { access(p); remove_left(p); } int depth(node *u) { u = access(u); return size(u); } node *lca(node *u, node *v) { if(u == v) { return u; } if(depth(u) > depth(v)) { swap(u, v); } access(v); access(u); return get_root(v)->pp; } /// normal functions void init(int c) { for(int i = 0; i <= c; i++) { ver[i] = new node(i); } } inline int lca(int u, int v) { return lca(ver[u], ver[v])->id; } inline int root(int u) { return find_root(ver[u])->id; } inline void link(int u, int v) { link(ver[u], ver[v]); } inline void make_root(int u) { make_root(ver[u]); } inline int depth(int u) { return depth(ver[u]); } inline void cut(int u) { cut(ver[u]); } }; int n, m; void read() { cin >> n >> m; } link_cut_tree lct; void solve() { lct.init(n); while(m--) { string type; cin >> type; if(type == "add") { int u, w; cin >> u >> w; lct.link(u, w); } else if(type == "conn") { int u, v; cin >> u >> v; cout << (lct.root(u) == lct.root(v) ? "YES" : "NO") << endl; } else if(type == "rem") { int u, v; cin >> u >> v; if(lct.depth(u) > lct.depth(v)) { swap(u, v); } lct.cut(v); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: old_impl/tree/virtual_tree.cpp ================================================ #include using namespace std; const int MAXLOG = 20; int n; vector> adj; void read() { cin >> n; adj.assign(n + 1, {}); for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } vector in_time, out_time; vector> par_up; void dfs_lca(int u, int pr, int &dfs_time) { in_time[u] = ++dfs_time; par_up[u].resize(MAXLOG); par_up[u][0] = pr; for(int i = 1; i < MAXLOG; i++) { par_up[u][i] = par_up[par_up[u][i - 1]][i - 1]; } for(int v: adj[u]) { if(v != pr) { dfs_lca(v, u, dfs_time); } } out_time[u] = dfs_time; } inline bool upper(int u, int v) { return in_time[u] <= in_time[v] && out_time[v] <= out_time[u]; } int lca(int u, int v) { if(upper(u, v)) { return u; } if(upper(v, u)) { return v; } int a = u; for(int i = MAXLOG - 1; i >= 0; i--) { if(!upper(par_up[a][i], v)) { a = par_up[a][i]; } } return par_up[a][0]; } void lca_precompute(int root) { int dfs_time = 0; in_time.resize(n + 1); out_time.resize(n + 1); par_up.resize(n + 1); dfs_lca(root, root, dfs_time); } vector> vg; int build_tree(vector vec) { if(vec.empty()) { return -1; } function cmp = [&](int u, int v) { return in_time[u] < in_time[v]; }; function &)> propagate_stack = [&](stack &mstack) { int prev_top = mstack.top(); mstack.pop(); vg[mstack.top()].push_back(prev_top); }; sort(vec.begin(), vec.end(), cmp); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int i = (int)vec.size() - 1; i > 0; i--) { vec.push_back(lca(vec[i - 1], vec[i])); } sort(vec.begin(), vec.end(), cmp); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int vertex: vec) { vg[vertex].clear(); } stack mstack; mstack.push(vec[0]); for(int i = 1; i < (int)vec.size(); i++) { while(!upper(mstack.top(), vec[i])) { propagate_stack(mstack); } mstack.push(vec[i]); } while(mstack.size() > 1) { propagate_stack(mstack); } return mstack.top(); } void solve() { lca_precompute(1); vg.assign(n + 1, {}); int q; cin >> q; for(int i = 0; i < q; i++) { int x, xx; cin >> x; vector vec; for(int i = 0; i < x; i++) { cin >> xx; vec.push_back(xx); } int root = build_tree(vec); } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/bits/bit_trie.hpp ================================================ #include using namespace std; template class BitTrie { public: struct node { array to; int cnt; node() { to = {-1, -1}; cnt = 0; } }; vector trie; void clear() { trie = {node()}; } BitTrie() { clear(); } void add(T x, int cnt) { int u = 0; trie[0].cnt += cnt; for(int i = num_bits - 1; i >= 0; i--) { int bit = (x >> i) & 1; if(trie[u].to[bit] == -1) { trie[u].to[bit] = (int)trie.size(); trie.push_back(node()); } u = trie[u].to[bit]; trie[u].cnt += cnt; } } T max_xor(T x) { int u = 0; T res = 0; for(int i = num_bits - 1; i >= 0; i--) { int bit = (x >> i) & 1; if(trie[u].to[bit ^ 1] != -1 && trie[trie[u].to[bit ^ 1]].cnt > 0) { res |= (T)1 << i; u = trie[u].to[bit ^ 1]; } else { u = trie[u].to[bit]; } } return res; } }; ================================================ FILE: other/bits/xor_basis.hpp ================================================ #include using namespace std; template class XorBasis { public: int sz; vector base; void clear() { sz = 0; base.assign(num_bits, nullptr); } XorBasis() { clear(); } void add(T val) { for(int i = num_bits - 1; i >= 0; i--) { if(get_bit(val, i)) { if(!base[i]) { base[i] = new T(val); sz++; return; } else { val = xor_op(val, *base[i]); } } } } inline int size() { return sz; } T max_xor() { T res = T(); for(int i = num_bits - 1; i >= 0; i--) { if(!get_bit(res, i) && base[i]) { res = xor_op(res, *base[i]); } } return res; } bool can_create(T val) { for(int i = num_bits - 1; i >= 0; i--) { if(get_bit(val, i) && base[i]) { val = xor_op(val, *base[i]); } } return is_zero(val); } vector get_basis() { vector res; for(int i = 0; i < num_bits; i++) { if(!base[i]) { res.push_back(*base[i]); } } return res; } XorBasis merge(const XorBasis& other) { if(sz < other.size()) { return other.merge(*this); } XorBasis res = *this; for(auto x: other.base) { if(x) { res.add(*x); } } return res; } private: // Helper functions for different types // For integral types template typename enable_if::value, bool>::type get_bit( const T& val, int pos ) const { return (val >> pos) & 1; } template typename enable_if::value, bool>::type is_zero(const T& val ) const { return val == 0; } template typename enable_if::value, T>::type xor_op( const T& a, const T& b ) const { return a ^ b; } // For bitset template typename enable_if>::value, bool>::type get_bit( const bitset& val, int pos ) const { return val[pos]; } template typename enable_if>::value, bool>::type is_zero( const bitset& val ) const { return val.none(); } template typename enable_if>::value, bitset>::type xor_op( const bitset& a, const bitset& b ) const { return a ^ b; } }; ================================================ FILE: other/dp_optimizations/LiChao_dynamic.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int64_t inf = (int64_t)1e17 + 42; struct LiChao_max { struct line { int a, b; line() { a = 0; b = 0; } line(int _a, int _b) { a = _a; b = _b; } int64_t eval(int x) { return a * 1ll * x + (int64_t)b; } }; struct node { node *l, *r; line f; node() { f = line(); l = nullptr; r = nullptr; } node(int a, int b) { f = line(a, b); l = nullptr; r = nullptr; } node(line v) { f = v; l = nullptr; r = nullptr; } }; typedef node* pnode; pnode root; int sz; void init(int _sz) { sz = _sz + 1; root = nullptr; } void add_line(int a, int b) { line v = line(a, b); insert(v, -sz, sz, root); } int64_t query(int x) { return query(x, -sz, sz, root); } void insert(line &v, int l, int r, pnode &nd) { if(!nd) { nd = new node(v); return; } int64_t trl = nd->f.eval(l), trr = nd->f.eval(r); int64_t vl = v.eval(l), vr = v.eval(r); if(trl >= vl && trr >= vr) return; if(trl < vl && trr < vr) { nd->f = v; return; } int mid = (l + r) >> 1; if(trl < vl) swap(nd->f, v); if(nd->f.eval(mid) > v.eval(mid)) insert(v, mid + 1, r, nd->r); else swap(nd->f, v), insert(v, l, mid, nd->l); } int64_t query(int x, int l, int r, pnode &nd) { if(!nd) return -inf; if(l == r) return nd->f.eval(x); int mid = (l + r) >> 1; if(mid >= x) return max(nd->f.eval(x), query(x, l, mid, nd->l)); return max(nd->f.eval(x), query(x, mid + 1, r, nd->r)); } }; struct LiChao_min { struct line { int a, b; line() { a = 0; b = 0; } line(int _a, int _b) { a = _a; b = _b; } int64_t eval(int x) { return a * 1ll * x + (int64_t)b; } }; struct node { node *l, *r; line f; node() { f = line(); l = nullptr; r = nullptr; } node(int a, int b) { f = line(a, b); l = nullptr; r = nullptr; } node(line v) { f = v; l = nullptr; r = nullptr; } }; typedef node* pnode; pnode root; int sz; void init(int _sz) { sz = _sz + 1; root = nullptr; } void add_line(int a, int b) { line v = line(a, b); insert(v, -sz, sz, root); } int64_t query(int x) { return query(x, -sz, sz, root); } void insert(line &v, int l, int r, pnode &nd) { if(!nd) { nd = new node(v); return; } int64_t trl = nd->f.eval(l), trr = nd->f.eval(r); int64_t vl = v.eval(l), vr = v.eval(r); if(trl <= vl && trr <= vr) return; if(trl > vl && trr > vr) { nd->f = v; return; } int mid = (l + r) >> 1; if(trl > vl) swap(nd->f, v); if(nd->f.eval(mid) < v.eval(mid)) insert(v, mid + 1, r, nd->r); else swap(nd->f, v), insert(v, l, mid, nd->l); } int64_t query(int x, int l, int r, pnode &nd) { if(!nd) return inf; if(l == r) return nd->f.eval(x); int mid = (l + r) >> 1; if(mid >= x) return min(nd->f.eval(x), query(x, l, mid, nd->l)); return min(nd->f.eval(x), query(x, mid + 1, r, nd->r)); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/dp_optimizations/LiChao_parabolic.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int inf = (int)1e9 + 42; template struct LiChao_parabolic_min { struct Parabol { T a, b, c; Parabol() {a = 0; b = 0; c = inf;} Parabol(T a, T b, T c) : a(a), b(b), c(c) {} Parabol(const Parabol& rhs) { a = rhs.a; b = rhs.b; c = rhs.c; } T query(T x) { return a * x * x + b * x + c; } }; struct Node { Parabol prb; Node *l, *r; Node() : l(0), r(0) {} T query(T x) { return prb.query(x); } }; Node* rt; T offset; vector mem; LiChao_parabolic_min() : rt(0), offset(0) {} Node* upd(Node* p, int l, int r, int L, int R, Parabol prb) { int M = (L + R) >> 1; if (l > R || r < L) return p; if (!p) p = new Node(); if (l <= L && r >= R) { if (prb.query(L) >= p->query(L) && prb.query(R) >= p->query(R)) { return p; } if (prb.query(L) <= p->query(L) && prb.query(R) <= p->query(R)) { p->prb = prb; return p; } if (prb.query(L) >= p->query(L) && prb.query(M) >= p->query(M)) { p->r = upd(p->r, l, r, M + 1, R, prb); return p; } if (prb.query(L) <= p->query(L) && prb.query(M) <= p->query(M)) { p->r = upd(p->r, l, r, M + 1, R, p->prb); p->prb = prb; return p; } if (prb.query(M + 1) >= p->query(M + 1) && prb.query(R) >= p->query(R)) { p->l = upd(p->l, l, r, L, M, prb); return p; } if (prb.query(M + 1) <= p->query(M + 1) && prb.query(R) <= p->query(R)) { p->l = upd(p->l, l, r, L, M, p->prb); p->prb = prb; return p; } return p; } else if (L < R) { p->l = upd(p->l, l, r, L, (L + R) >> 1, prb); p->r = upd(p->r, l, r, ((L + R) >> 1) + 1, R, prb); } } T query(Node* p, int i, int L, int R) { if (!p) return inf; if (i < L || i > R) return inf; T res = inf; res = min(res, p->query(i)); if (L < R) { res = min(res, query(p->l, i, L, (L + R) >> 1)); res = min(res, query(p->r, i, ((L + R) >> 1) + 1, R)); } return res; } void upd(T a, T b, T c) { mem.push_back(Parabol(a, b, c)); rt = upd(rt, 0, 100005, 0, 100005, Parabol(a, b, c)); } T query(int i) { return query(rt, i, 0, 100005); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/dp_optimizations/LiChao_segment_tree_offline.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const double inf = (double)1e17 + 42; struct LiChao_max { struct line { double a, b; line() { a = 0; b = 0; } line(double _a, double _b) { a = _a; b = _b; } double eval(int x) { return a * x + b; } }; line tr[4 * MAXN]; bool vis[4 * MAXN]; int value[MAXN]; int sz; void init(int l, int r, int idx) { if(r < l) return; vis[idx] = 0; if(l == r) return; int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); } void init(vector Q) { sort(Q.begin(), Q.end()); Q.erase(unique(Q.begin(), Q.end()), Q.end()); sz = Q.size(); for(int i = 0; i < (int)Q.size(); i++) value[i + 1] = Q[i]; init(1, sz, 0); } void add_line(double a, double b) { line v = line(a, b); insert(v, 1, sz, 0); } double query(int x) { return query(x, 1, sz, 0); } void insert(line &v, int l, int r, int idx) { if(!vis[idx]) { tr[idx] = v; vis[idx] = true; return; } double trl = tr[idx].eval(value[l]), trr = tr[idx].eval(value[r]), vl = v.eval(value[l]), vr = v.eval(value[r]); if(trl >= vl && trr >= vr) return; if(trl < vl && trr < vr) { tr[idx] = v; return; } int mid = (l + r) >> 1; if(trl < vl) swap(tr[idx], v); if(tr[idx].eval(value[mid]) > v.eval(value[mid])) insert(v, mid + 1, r, 2 * idx + 2); else swap(tr[idx], v), insert(v, l, mid, 2 * idx + 1); } double query(int x, int l, int r, int idx) { if(!vis[idx]) return -inf; if(l == r) return tr[idx].eval(x); int mid = (l + r) >> 1; if(value[mid] >= x) return max(tr[idx].eval(x), query(x, l, mid, 2 * idx + 1)); return max(tr[idx].eval(x), query(x, mid + 1, r, 2 * idx + 2)); } }; struct LiChao_min { struct line { double a, b; line() { a = 0; b = 0; } line(double _a, double _b) { a = _a; b = _b; } double eval(int x) { return a * x + b; } }; line tr[4 * MAXN]; bool vis[4 * MAXN]; int value[MAXN]; int sz; void init(int l, int r, int idx) { if(r < l) return; vis[idx] = 0; if(l == r) return; int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1); init(mid + 1, r, 2 * idx + 2); } void init(vector Q) { sort(Q.begin(), Q.end()); Q.erase(unique(Q.begin(), Q.end()), Q.end()); sz = Q.size(); for(int i = 0; i < (int)Q.size(); i++) value[i + 1] = Q[i]; init(1, sz, 0); } void add_line(double a, double b) { line v = line(a, b); insert(v, 1, sz, 0); } double query(int x) { return query(x, 1, sz, 0); } void insert(line &v, int l, int r, int idx) { if(!vis[idx]) { tr[idx] = v; vis[idx] = true; return; } double trl = tr[idx].eval(value[l]), trr = tr[idx].eval(value[r]), vl = v.eval(value[l]), vr = v.eval(value[r]); if(trl <= vl && trr <= vr) return; if(trl > vl && trr > vr) { tr[idx] = v; return; } int mid = (l + r) >> 1; if(trl > vl) swap(tr[idx], v); if(tr[idx].eval(value[mid]) < v.eval(value[mid])) insert(v, mid + 1, r, 2 * idx + 2); else swap(tr[idx], v), insert(v, l, mid, 2 * idx + 1); } double query(int x, int l, int r, int idx) { if(!vis[idx]) return inf; if(l == r) return tr[idx].eval(x); int mid = (l + r) >> 1; if(value[mid] >= x) return min(tr[idx].eval(x), query(x, l, mid, 2 * idx + 1)); return min(tr[idx].eval(x), query(x, mid + 1, r, 2 * idx + 2)); } }; void read() { } void solve() { } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/dp_optimizations/convex_hull_trick_max.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int64_t inf = (int64_t)1e18 + 42; struct convex_hull_trick_max { struct line { int64_t m, b; bool is_query; double line_x; line() {m = 0; b = 0; line_x = 0; is_query = 0; } line(int64_t _m, int64_t _b) {m = _m; b = _b; line_x = 0; is_query = 0; } bool operator<(const line &l2) const { if(!is_query && !l2.is_query) return m < l2.m; else return line_x < l2.line_x; } int64_t value_at(int64_t x) const { return m * x + b; } }; bool parallel(const line &l1, const line &l2) { return l1.m == l2.m; } double intersect_x(const line &l1, const line &l2) { if(parallel(l1, l2)) return (double)inf; return (double)(l1.b - l2.b) / (double)(l2.m - l1.m); } set hull; void clear() { hull.clear(); } void init() { clear(); } bool has_next(set::iterator it) { return it != hull.end() && next(it) != hull.end(); } bool has_prev(set::iterator it) { return it != hull.end() && it != hull.begin(); } bool irrelevant(const line &l1, const line &l2, const line &l3) { return intersect_x(l1, l3) <= intersect_x(l1, l2); } bool irrelevant(set::iterator it) { return has_prev(it) && has_next(it) && irrelevant(*prev(it), *it, *next(it)); } set::iterator update_border(set::iterator it) { line tmp(*it); double val; if(has_next(it)) val = intersect_x(*it, *next(it)); else val = inf; it = hull.erase(it); tmp.line_x = val; it = hull.insert(it, tmp); return it; } void add_line(int64_t m, int64_t b) { line curr_line = line(m, b); set::iterator it = hull.lower_bound(curr_line); if(it != hull.end() && it->m == m) { if(it->b < b) it = hull.erase(it); else return; } it = hull.insert(it, curr_line); if(irrelevant(it)) { hull.erase(it); return; } while(has_prev(it) && irrelevant(prev(it))) hull.erase(prev(it)); while(has_next(it) && irrelevant(next(it))) hull.erase(next(it)); it = update_border(it); if(has_prev(it)) update_border(prev(it)); if(has_next(it)) update_border(next(it)); } int64_t query(int64_t x) { line to_find; to_find.line_x = x; to_find.is_query = 1; set::iterator best_line = hull.lower_bound(to_find); if(best_line == hull.end()) return inf; return best_line->value_at(x); } }; void read() { } convex_hull_trick_max cht; void solve() { cht.init(); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/dp_optimizations/convex_hull_trick_min.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); const int64_t inf = (int64_t)1e18 + 42; struct convex_hull_trick_min { struct line { int64_t m, b; bool is_query; double line_x; line() {m = 0; b = 0; line_x = 0; is_query = 0; } line(int64_t _m, int64_t _b) {m = _m; b = _b; line_x = 0; is_query = 0; } bool operator<(const line &l2) const { if(!is_query && !l2.is_query) return m > l2.m; else return line_x < l2.line_x; } int64_t value_at(int64_t x) const { return m * x + b; } }; bool parallel(const line &l1, const line &l2) { return l1.m == l2.m; } double intersect_x(const line &l1, const line &l2) { if(parallel(l1, l2)) return (double)inf; return (double)(l1.b - l2.b) / (double)(l2.m - l1.m); } set hull; void clear() { hull.clear(); } void init() { clear(); } bool has_next(set::iterator it) { return it != hull.end() && next(it) != hull.end(); } bool has_prev(set::iterator it) { return it != hull.end() && it != hull.begin(); } bool irrelevant(const line &l1, const line &l2, const line &l3) { return intersect_x(l1, l3) <= intersect_x(l1, l2); } bool irrelevant(set::iterator it) { return has_prev(it) && has_next(it) && irrelevant(*prev(it), *it, *next(it)); } set::iterator update_border(set::iterator it) { line tmp(*it); double val; if(has_next(it)) val = intersect_x(*it, *next(it)); else val = inf; it = hull.erase(it); tmp.line_x = val; it = hull.insert(it, tmp); return it; } void add_line(int64_t m, int64_t b) { line curr_line = line(m, b); set::iterator it = hull.lower_bound(curr_line); if(it != hull.end() && it->m == m) { if(it->b > b) it = hull.erase(it); else return; } it = hull.insert(it, curr_line); if(irrelevant(it)) { hull.erase(it); return; } while(has_prev(it) && irrelevant(prev(it))) hull.erase(prev(it)); while(has_next(it) && irrelevant(next(it))) hull.erase(next(it)); it = update_border(it); if(has_prev(it)) update_border(prev(it)); if(has_next(it)) update_border(next(it)); } int64_t query(int64_t x) { line to_find; to_find.line_x = x; to_find.is_query = 1; set::iterator best_line = hull.lower_bound(to_find); if(best_line == hull.end()) return inf; return best_line->value_at(x); } }; void read() { } convex_hull_trick_min cht; void solve() { cht.init(); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/dp_optimizations/divide_and_conquer_optimization.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (int)4e3 + 42; const int inf = (int)1e9 + 42; void Read(int &x); int n, m; void read() { } int dp[MAXN][MAXN], cost[MAXN][MAXN]; void rec(int l, int r, int opt_l, int opt_r, int k) { if(r < l) return; if(l == r) { dp[l][k] = inf; for(int i = opt_l; i <= min(opt_r, l); i++) if(dp[l][k] > dp[i - 1][k - 1] + cost[i][l]) dp[l][k] = dp[i - 1][k - 1] + cost[i][l]; return; } int mid = (l + r) >> 1, copt = opt_l; dp[mid][k] = inf; for(int i = opt_l; i <= min(mid, opt_r); i++) if(dp[mid][k] > dp[i - 1][k - 1] + cost[i][mid]) { dp[mid][k] = dp[i - 1][k - 1] + cost[i][mid]; copt = i; } rec(l, mid - 1, opt_l, copt, k); rec(mid + 1, r, copt, opt_r, k); } void solve() { for(int i = 0; i <= n; i++) dp[i][0] = inf; for(int i = 0; i <= m; i++) dp[0][i] = 0; for(int k = 1; k <= m; k++) rec(1, n, 1, n, k); } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } #define maxl 100000 char sir[maxl]; int pos_ind = 0; void Next() { if(++pos_ind == maxl) fread(sir, 1, maxl, stdin), pos_ind = 0; } void Read(int &x) { for(; sir[pos_ind] < '0' || sir[pos_ind] > '9'; Next()); for(x = 0; sir[pos_ind] >= '0' && sir[pos_ind] <= '9'; Next()) x = x * 10 + sir[pos_ind] - '0'; } ================================================ FILE: other/dp_optimizations/slope_trick.cpp ================================================ #include #define endl '\n' #define SZ(x) ((int)x.size()) #define ALL(V) V.begin(), V.end() #define lb lower_bound #define ub upper_bound #define pb push_back using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } const int MAXN = (1 << 20); template struct slope_trick { T offset_l, offset_r, zero_height; multiset L; multiset R; slope_trick() { offset_l = 0; offset_r = 0; zero_height = 0; } T zero_start() { if(L.empty()) { return numeric_limits::min(); } else { return *L.rbegin() + offset_l; } } T zero_end() { if(R.empty()) { return numeric_limits::max(); } else { return *R.begin() + offset_r; } } inline size_t size() { return L.size() + R.size(); } /* Add the function f(x) = height + |x - center| to the current slope trick. */ void add_simple(const T ¢er, const T &height = 0) { T s = zero_start(), e = zero_end(); zero_height += height; if(s <= center && center <= e) { L.insert(center - offset_l); R.insert(center - offset_r); } else if(center < s) { L.insert(center - offset_l); L.insert(center - offset_l); L.erase(prev(L.end())); R.insert(s - offset_r); zero_height += abs(center - s); } else { R.insert(center - offset_r); R.insert(center - offset_r); R.erase(R.begin()); L.insert(e - offset_l); zero_height += abs(center - e); } } /* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' <= x. */ void prefix_min() { offset_r = 0; R.clear(); } /* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' >= x. */ void suffix_min() { offset_l = 0; L.clear(); } /* Update the current slope trick to its local minimum - i.e. f'(x) = min f(x') for all x - strip_width <= x' <= x + strip_width. */ void local_min(const T &strip_width) { if(!L.empty()) { offset_l -= strip_width; } if(!R.empty()) { offset_r += strip_width; } } void add(const slope_trick &other) { // TODO: Add arbitrary slope trick. } void add_with_destroy(slope_trick &other) { // TODO: Add using small to large. } }; int n; int a[MAXN]; void read() { cin >> n; for(int i = 0; i < n; i++) { cin >> a[i]; } } void solve() { slope_trick dp; for(int i = 0; i < n; i++) { a[i] -= i; dp.add_simple(a[i]); dp.prefix_min(); } cout << dp.zero_height << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int T = 1; //cin >> T; for(int test = 1; test <= T; test++) { read(); //cout << "Case #" << test << ": "; solve(); } return 0; } ================================================ FILE: other/dp_optimizations/slope_trick_priority_queue.cpp ================================================ #include #define endl '\n' #define SZ(x) ((int)x.size()) #define ALL(V) V.begin(), V.end() #define lb lower_bound #define ub upper_bound #define pb push_back using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } const int MAXN = (1 << 20); template struct slope_trick { T offset_l, offset_r, zero_height; priority_queue L; priority_queue, greater> R; slope_trick() { offset_l = 0; offset_r = 0; zero_height = 0; } T zero_start() { if(L.empty()) { return numeric_limits::min(); } else { return L.top() + offset_l; } } T zero_end() { if(R.empty()) { return numeric_limits::max(); } else { return R.top() + offset_r; } } /* Add the function f(x) = height + |x - center| to the current slope trick. */ void add_simple(const T ¢er, const T &height = 0) { T s = zero_start(), e = zero_end(); zero_height += height; if(s <= center && center <= e) { L.push(center - offset_l); R.push(center - offset_r); } else if(center < s) { L.push(center - offset_l); L.push(center - offset_l); L.pop(); R.push(s - offset_r); zero_height += abs(center - s); } else { R.push(center - offset_r); R.push(center - offset_r); R.pop(); L.push(e - offset_l); zero_height += abs(center - e); } } /* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' <= x. */ void prefix_min() { offset_r = 0; while(!R.empty()) { R.pop(); } } /* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' >= x. */ void suffix_min() { offset_l = 0; while(!L.empty()) { L.pop(); } } /* Update the current slope trick to its local minimum - i.e. f'(x) = min f(x') for all x - strip_width <= x' <= x + strip_width. */ void local_min(const T &strip_width) { if(!L.empty()) { offset_l -= strip_width; } if(!R.empty()) { offset_r += strip_width; } } }; int n; int a[MAXN]; void read() { cin >> n; for(int i = 0; i < n; i++) { cin >> a[i]; } } void solve() { slope_trick dp; for(int i = 0; i < n; i++) { a[i] -= i; dp.add_simple(a[i]); dp.prefix_min(); } cout << dp.zero_height << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int T = 1; //cin >> T; for(int test = 1; test <= T; test++) { read(); //cout << "Case #" << test << ": "; solve(); } return 0; } ================================================ FILE: other/queries/mo.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct query { int l, r, block; int idx; query() {l = -1; r = -1; block = -1; idx = -1;} query(int _l, int _r, int i) { l = _l; r = _r; idx = i; } }; bool cmp(query a, query b) { if(a.block != b.block) return a.block < b.block; return a.r < b.r; } int n, m, len, sq, item; void read() { cin >> n >> m; } int ans, answer[MAXN]; void add(int idx) { } void del(int idx) { } query q[MAXN]; void solve() { for(int i = 0; i < m; i++) { int l, r; cin >> l >> r; q[i] = query(l - 1, r - 1, i); } sq = sqrt(n); for(int i = 0; i < m; i++) q[i].block = q[i].l / sq; sort(q, q + m, cmp); int l = q[0].l, r = q[0].r; for(int i = l; i <= r; i++) add(i); for(int i = 0; i < m; i++) { while(l < q[i].l) del(l++); while(l > q[i].l) add(--l); while(r < q[i].r) add(++r); while(r > q[i].r) del(r--); answer[q[i].idx] = ans; } for(int i = 0; i < m; i++) cout << answer[i] << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/queries/mo_dsu.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (1 << 20); struct query { int l, r, idx; query() {l = 0; r = 0; idx = 0;} query(int _l, int _r, int _idx) { l = _l; r = _r; idx = _idx; } }; struct persistent_dsu { struct state { int u, ru, v, rv; state() {u = 0; ru = 0; v = 0; rv = 0;} state(int _u, int _ru, int _v, int _rv) { u = _u; ru = _ru; v = _v; rv = _rv; } }; int cnt; int depth[MAXN], par[MAXN]; stack st; persistent_dsu() { cnt = 0; memset(depth, 0, sizeof(depth)); memset(par, 0, sizeof(par)); while(!st.empty()) st.pop(); } void init(int _sz) { cnt = _sz; for(int i = 0; i <= _sz; i++) par[i] = i, depth[i] = 1; } int root(int x) { if(x == par[x]) return x; return root(par[x]); } bool connected(int x, int y) { return root(x) == root(y); } void unite(int x, int y) { int rx = root(x), ry = root(y); if(rx == ry) return; if(depth[rx] < depth[ry]) par[rx] = ry; else if(depth[ry] < depth[rx]) par[ry] = rx; else par[rx] = ry, depth[ry]++; cnt--; st.push(state(rx, depth[rx], ry, depth[ry])); } void snapshot() { st.push(state(-1, -1, -1, -1)); } void rollback() { while(!st.empty()) { if(st.top().u == -1) return; ++cnt; par[st.top().u] = st.top().u; par[st.top().v] = st.top().v; depth[st.top().u] = st.top().ru; depth[st.top().v] = st.top().rv; st.pop(); } } }; struct edge { int u, v; edge() {u = 0; v = 0;} edge(int _u, int _v) { u = _u; v = _v; } }; int n, ed, m; edge a[MAXN]; query q[MAXN]; void read() { cin >> n >> ed >> m; for(int i = 1; i <= ed; i++) { int u, v; cin >> u >> v; a[i] = edge(u, v); } } int rt, cnt_q; persistent_dsu d; bool cmp(query fir, query sec) { if(fir.l / rt != sec.l / rt) return fir.l / rt < sec.l / rt; return fir.r < sec.r; } int answer[MAXN]; void add(int idx) { d.unite(a[idx].u, a[idx].v); } void solve() { d.init(n); d.snapshot(); rt = sqrt(ed); cnt_q = 0; int fm = m; for(int i = 0; i < m; i++) { int l, r; cin >> l >> r; if(r - l + 1 <= rt) { for(int k = l; k <= r; k++) add(k); answer[i] = d.cnt; d.rollback(); continue; } q[cnt_q++] = query(l, r, i); } m = cnt_q; sort(q, q + m, cmp); int last, border, last_block = -1, block; for(int i = 0; i < m; i++) { block = q[i].l / rt; if(last_block != block) { d.init(n); border = rt * (block + 1); last = border; } last_block = block; for(int k = last + 1; k <= q[i].r; k++) add(k); d.snapshot(); for(int k = q[i].l; k <= border; k++) add(k); answer[q[i].idx] = d.cnt; d.rollback(); last = q[i].r; } for(int i = 0; i < fm; i++) cout << answer[i] << endl; } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/queries/mo_online.cpp ================================================ #include #define endl '\n' using namespace std; const int MAXN = (int)1e5 + 42; const int B = 2172; int n, q; int a[MAXN]; void read() { cin >> n >> q; for(int i = 0; i < n; i++) cin >> a[i]; } struct my_set { int answer; unordered_map cnt; my_set() { answer = 0; cnt.clear(); } void insert(int val) { int memo = ++cnt[val]; if(memo == 1) answer++; } void erase(int val) { int memo = --cnt[val]; if(memo == 0) answer--; } void clear() { answer = 0; cnt.clear(); } int query() { return answer; } }; int st_block[MAXN / B + 42], en_block[MAXN / B + 42], cnt_blocks = 0; my_set st[(MAXN / B + 1) * (MAXN / B + 1) + 42], nw_st; int query(int l, int r) { int Lblock = l / B, Rblock = r / B; if(r != en_block[Rblock]) Rblock--; if(l != st_block[Lblock]) Lblock++; if(Rblock < Lblock) { nw_st.clear(); for(int i = l; i <= r; i++) nw_st.insert(a[i]); return nw_st.query(); } int mid = Lblock * cnt_blocks + Rblock; for(int i = l; i < st_block[Lblock]; i++) st[mid].insert(a[i]); for(int i = en_block[Rblock] + 1; i <= r; i++) st[mid].insert(a[i]); int answer = st[mid].query(); for(int i = l; i < st_block[Lblock]; i++) st[mid].erase(a[i]); for(int i = en_block[Rblock] + 1; i <= r; i++) st[mid].erase(a[i]); return answer; } void update(int mid, int pos, int val) { st[mid].erase(a[pos]); st[mid].insert(val); } void solve() { for(int i = 0; i < n; i++) { if(i % B == 0) st_block[i / B] = i, cnt_blocks++; if(i % B == B - 1 || i == n - 1) en_block[i / B] = i; } for(int i = 0; i < cnt_blocks; i++) for(int j = i; j < cnt_blocks; j++) { int mid = i * cnt_blocks + j; st[mid] = my_set(); for(int p = st_block[i]; p <= en_block[j]; p++) st[mid].insert(a[p]); } for(int p = 0; p < q; p++) { int type; cin >> type; if(type == 1) { int l, r; cin >> l >> r; cout << query(l, r) << endl; } else { int pos, val; cin >> pos >> val; for(int i = 0; i < cnt_blocks; i++) for(int j = i; j < cnt_blocks; j++) if(st_block[i] <= pos && pos <= en_block[j]) update(i * cnt_blocks + j, pos, val); a[pos] = val; } } } int main() { ios_base::sync_with_stdio(false); cin.tie(NULL); read(); solve(); return 0; } ================================================ FILE: other/queries/offline_centroid_queries.cpp ================================================ // This is from https://codeforces.com/contest/1902/problem/F #include using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } template ostream &operator<<(ostream &out, const pair &x) { return out << x.first << ' ' << x.second; } template istream &operator>>(istream &in, pair &x) { return in >> x.first >> x.second; } template istream &operator>>(istream &in, vector &a) { for(auto &x: a) { in >> x; } return in; }; template ostream &operator<<(ostream &out, vector &a) { for(auto &x: a) { out << x << ' '; } return out; }; template struct basis { int max_log; vector base; void init(int _max_log) { max_log = _max_log; base.assign(max_log, 0); } void add(T val) { for(int i = max_log - 1; i >= 0; i--) { if((val >> i) & 1) { if(!base[i]) { base[i] = val; return; } else { val ^= base[i]; } } } } inline int size() { int sz = 0; for(int i = 0; i < max_log; i++) { sz += (bool)(base[i]); } return sz; } T max_xor() { T res = 0; for(int i = max_log - 1; i >= 0; i--) { if(!((res >> i) & 1) && base[i]) { res ^= base[i]; } } return res; } bool can_create(T val) { for(int i = max_log - 1; i >= 0; i--) { if(((val >> i) & 1) && base[i]) { val ^= base[i]; } } return (val == 0); } vector get_basis() { vector res; for(int i = 0; i < max_log; i++) { if(base[i]) { res.push_back(base[i]); } } return res; } basis merge(basis other) { if(max_log < other.max_log) { return other.merge(*this); } basis res = *this; for(auto x: other.base) { if(x) { res.add(x); } } return res; } }; const int MAXLOG = 20; int n; vector> adj; vector a; void read() { cin >> n; adj.assign(n, {}); a.resize(n); cin >> a; for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; u--, v--; adj[u].push_back(v); adj[v].push_back(u); } } vector> bs; vector, int>> queries; vector ans, sz, marker; vector used; int get_size(int v, int p) { sz[v] = 1; for(int u: adj[v]) { if(u != p && !used[u]) { sz[v] += get_size(u, v); } } return sz[v]; } void dfs_basis(int v, int p, basis pref_bs) { basis nw_bs = pref_bs; nw_bs.add(a[v]); bs[v] = nw_bs; for(auto u: adj[v]) { if(u != p && !used[u]) { dfs_basis(u, v, nw_bs); } } } void dfs_marker(int v, int p, int mark) { marker[v] = mark; for(int u: adj[v]) { if(u != p && !used[u]) { dfs_marker(u, v, mark); } } } void decompose(int u, vector qidx) { get_size(u, -1); int n = sz[u], centroid = u, p = -1; while(true) { int nxt = -1; for(int v: adj[centroid]) { if(v != p && !used[v] && sz[v] > n / 2) { nxt = v; break; } } if(nxt != -1) { p = centroid; centroid = nxt; } else { break; } } used[centroid] = true; basis pref_bs; pref_bs.init(MAXLOG); pref_bs.add(a[centroid]); bs[centroid] = pref_bs; int mark = 0; vector> children_queries(adj[centroid].size()); for(int v: adj[centroid]) { if(!used[v]) { dfs_marker(v, centroid, mark); dfs_basis(v, centroid, pref_bs); } mark++; } marker[centroid] = mark; for(int idx: qidx) { auto [xy, k] = queries[idx]; auto [x, y] = xy; if(marker[x] == marker[y] && x != centroid) { children_queries[marker[x]].push_back(idx); } else { basis q_basis = bs[x].merge(bs[y]); if(q_basis.can_create(k)) { ans[idx] = 1; } else { ans[idx] = 0; } } } int i = 0; for(int v: adj[centroid]) { if(!used[v] && children_queries[i].size() > 0) { decompose(v, children_queries[i]); } i++; } } void solve() { bs.resize(n); sz.resize(n); used.assign(n, false); marker.assign(n, 0); int q; cin >> q; queries.resize(q); for(int i = 0; i < q; i++) { int x, y, k; cin >> x >> y >> k; x--, y--; queries[i] = {{x, y}, k}; } vector qidx(q); ans.resize(q); iota(qidx.begin(), qidx.end(), 0); decompose(0, qidx); for(int i = 0; i < q; i++) { if(ans[i] == 1) { cout << "YES\n"; } else { cout << "NO\n"; } } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); int T = 1; // cin >> T; for(int test = 1; test <= T; test++) { read(); // cout << "Case #" << test << ": "; solve(); } return 0; } ================================================ FILE: other/utils/count_inversions.cpp ================================================ #include using namespace std; int64_t count_inversions(int *start, int *end) { if(end - start <= 1) { return 0; } int *mid = start + (end - start) / 2; int64_t ans = count_inversions(start, mid) + count_inversions(mid, end); vector temp; for(int *i = start, *j = mid; i != mid || j != end; ) { if(i == mid) { temp.push_back(*j++); } else if(j == end) { temp.push_back(*i++); } else if(*i <= *j) { temp.push_back(*i++); } else { ans += mid - i; temp.push_back(*j++); } } copy(temp.begin(), temp.end(), start); return ans; } ================================================ FILE: strings/aho_corasick.hpp ================================================ #include using namespace std; template class AhoCorasick { private: using G = conditional_t< is_same_v || is_same_v || is_array_v, char, typename T::value_type>; struct State { map to; int link; int word_id; State() : link(0), word_id(-1) {} }; public: vector states; AhoCorasick() { clear(); } void clear() { states.clear(); states.emplace_back(); } void add_word(const T& word, int id = -1) { int u = 0; for(const G& c: word) { if(!states[u].to.count(c)) { states[u].to[c] = states.size(); states.emplace_back(); } u = states[u].to[c]; } states[u].word_id = id; } void build() { queue Q; states[0].link = -1; for(auto& [c, v]: states[0].to) { states[v].link = 0; Q.push(v); } while(!Q.empty()) { int u = Q.front(); Q.pop(); for(auto& [c, v]: states[u].to) { int j = states[u].link; while(j != -1 && !states[j].to.count(c)) { j = states[j].link; } states[v].link = (j == -1) ? 0 : states[j].to[c]; Q.push(v); } } } int go(int u, const G& c) const { while(u != -1 && !states[u].to.count(c)) { u = states[u].link; } return (u == -1) ? 0 : states[u].to.at(c); } int link(int u) const { return states[u].link; } int word_id(int u) const { return states[u].word_id; } int size() const { return states.size(); } vector traverse(const T& text) const { vector result; result.reserve(text.size()); int u = 0; for(const G& c: text) { u = go(u, c); result.push_back(u); } return result; } vector> build_link_tree() const { vector> adj(states.size()); for(int i = 1; i < (int)states.size(); i++) { adj[states[i].link].push_back(i); } return adj; } }; ================================================ FILE: strings/hashing.hpp ================================================ #include using namespace std; class HashMeta { private: void set_random_base() { seed_seq seed{ (uint32_t)chrono::duration_cast( chrono::high_resolution_clock::now().time_since_epoch() ) .count(), (uint32_t)random_device()(), (uint32_t)42 }; mt19937 rng(seed); base = uniform_int_distribution(0, mod - 1)(rng); } void precompute_base_pow(size_t n) { base_pow.resize(n); base_pow[0] = 1; for(size_t i = 1; i < n; i++) { base_pow[i] = mul(base_pow[i - 1], base); } } static constexpr uint64_t add(uint64_t a, uint64_t b) { a += b + 1; a = (a & mod) + (a >> 61); return a - 1; } static constexpr uint64_t sub(uint64_t a, uint64_t b) { return add(a, mod - b); } static constexpr uint64_t mul(uint64_t a, uint64_t b) { uint64_t l1 = (uint32_t)a, h1 = a >> 32, l2 = (uint32_t)b, h2 = b >> 32; uint64_t l = l1 * l2, m = l1 * h2 + l2 * h1, h = h1 * h2; uint64_t ret = (l & mod) + (l >> 61) + (h << 3) + (m >> 29) + (m << 35 >> 3) + 1; ret = (ret & mod) + (ret >> 61); ret = (ret & mod) + (ret >> 61); return ret - 1; } public: class hash_t { uint64_t h; public: hash_t() : h(0) {} hash_t(uint64_t h) : h(h) {} operator uint64_t() const { return h; } hash_t& operator+=(const hash_t& other) { h = add(h, other.h); return *this; } hash_t& operator-=(const hash_t& other) { h = sub(h, other.h); return *this; } hash_t& operator*=(const hash_t& other) { h = mul(h, other.h); return *this; } hash_t operator+(const hash_t& other) const { return hash_t(*this) += other; } hash_t operator-(const hash_t& other) const { return hash_t(*this) -= other; } hash_t operator*(const hash_t& other) const { return hash_t(*this) *= other; } bool operator==(const hash_t& other) const { return h == other.h; } bool operator!=(const hash_t& other) const { return h != other.h; } // For use in std::map and std::set bool operator<(const hash_t& other) const { return h < other.h; } }; uint64_t base; vector base_pow; static constexpr uint64_t mod = (1ull << 61) - 1; void init(size_t n) { set_random_base(); precompute_base_pow(n); } template vector rabin_karp(const T& container) { vector h(container.size()); for(size_t i = 0; i < container.size(); i++) { h[i] = (i ? h[i - 1] : hash_t(0)) * hash_t(base) + hash_t(container[i]); } return h; } hash_t hash_range(int l, int r, const vector& h) { if(l == 0) { return h[r]; } return h[r] - h[l - 1] * base_pow[r - l + 1]; } }; // HashMeta hash_meta; // using hash_t = HashMeta::hash_t; ================================================ FILE: strings/suffix_array.hpp ================================================ #include using namespace std; template class SuffixArray { private: using G = conditional_t< is_same_v || is_same_v || is_array_v, char, typename T::value_type>; void build_sa(const T& s) { sa.resize(n); rnk.resize(n); vector tmp(n); for(int i = 0; i < n; i++) { sa[i] = i; rnk[i] = (int)s[i]; } for(int k = 1; k < n; k <<= 1) { auto cmp = [&](int x, int y) { if(rnk[x] != rnk[y]) { return rnk[x] < rnk[y]; } int rx = x + k < n ? rnk[x + k] : -1; int ry = y + k < n ? rnk[y + k] : -1; return rx < ry; }; sort(sa.begin(), sa.end(), cmp); tmp[sa[0]] = 0; for(int i = 1; i < n; i++) { tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0); } rnk = tmp; if(rnk[sa[n - 1]] == n - 1) { break; } } } void build_lcp(const T& s) { lcp.assign(n, 0); int h = 0; for(int i = 0; i < n; i++) { if(rnk[i] > 0) { int j = sa[rnk[i] - 1]; while(i + h < n && j + h < n && s[i + h] == s[j + h]) { h++; } lcp[rnk[i]] = h; if(h > 0) { h--; } } else { h = 0; } } } public: int n; vector sa, rnk, lcp; SuffixArray() : n(0) {} SuffixArray(const T& s) { init(s); } void clear() { n = 0; sa.clear(); rnk.clear(); lcp.clear(); } void init(const T& s) { clear(); n = (int)size(s); if(n == 0) { return; } build_sa(s); build_lcp(s); } }; ================================================ FILE: strings/suffix_automaton.hpp ================================================ #include using namespace std; template class SuffixAutomaton { private: using G = conditional_t< is_same_v || is_same_v || is_array_v, char, typename T::value_type>; struct State { map to; int len; int link; State(int l = 0, int lnk = -1) : len(l), link(lnk) {} }; int check_replace_with_clone(int p, G c) { int q = states[p].to[c]; if(states[p].len + 1 == states[q].len) { return q; } int clone = states.size(); states.emplace_back(states[p].len + 1, states[q].link); states[clone].to = states[q].to; while(p >= 0 && states[p].to[c] == q) { states[p].to[c] = clone; p = states[p].link; } states[q].link = clone; return clone; } public: int last; vector states; SuffixAutomaton() : last(0) { clear(); } SuffixAutomaton(const T& s) { init(s); } void add_letter(G c) { if(states[last].to.count(c)) { int clone = check_replace_with_clone(last, c); last = clone; return; } int p = last; last = states.size(); states.emplace_back(states[p].len + 1); while(p >= 0 && !states[p].to.count(c)) { states[p].to[c] = last; p = states[p].link; } if(p == -1) { states[last].link = 0; return; } int q_or_clone = check_replace_with_clone(p, c); states[last].link = q_or_clone; } void add_string(const T& s) { last = 0; for(char c: s) { add_letter(c); } } void clear() { states.clear(); states.emplace_back(); last = 0; } void init(const T& s) { clear(); add_string(s); } vector> build_suffix_link_tree() { vector> adj(states.size()); for(int i = 1; i < (int)states.size(); i++) { adj[states[i].link].push_back(i); } return adj; } vector> states_by_length() { vector> ret(states.size()); for(int i = 0; i < (int)states.size(); i++) { ret[states[i].len].push_back(i); } return ret; } }; ================================================ FILE: tree/centroid_decomposition.hpp ================================================ #include using namespace std; template< void (*process)(int, const vector> &, const vector &)> class CentroidDecomposition { private: int n; vector> adj; vector blocked; vector subtree_size; int dfs(int u, int pr) { subtree_size[u] = 1; for(int v: adj[u]) { if(v != pr && !blocked[v]) { subtree_size[u] += dfs(v, u); } } return subtree_size[u]; } int find_centroid(int u, int pr, int n) { for(int v: adj[u]) { if(v != pr && !blocked[v] && subtree_size[v] > n / 2) { return find_centroid(v, u, n); } } return u; } public: vector link, centroid_depth; CentroidDecomposition(vector> adj = {}, int root = 0) : adj(adj) { n = adj.size(); if(n > 0) { blocked.assign(n, false); link.assign(n, -1); centroid_depth.assign(n, -1); subtree_size.assign(n, 0); decompose(root); } } void decompose(int u, int prev_cen = -1, int depth = 0) { int n_here = dfs(u, -1); int cen = find_centroid(u, -1, n_here); link[cen] = prev_cen; centroid_depth[cen] = depth; process(cen, adj, blocked); blocked[cen] = true; for(int v: adj[cen]) { if(!blocked[v]) { decompose(v, cen, depth + 1); } } blocked[cen] = false; } }; // void blank_process(int, const vector> &, const vector &) {} // #include // LCAUtilsRMQ tr; // tr.init(n); // for(int i = 1; i < n; i++) { // tr.add_edge(i, p[i]); // } // tr.prepare(0); // Maintain closest active node query. // CentroidDecomposition cd(tr.adj); // vector>> best(n), to_remove(n); // function closest_active = [&](int u) { // int cen_root = u, ans_dist = -1, ans_node = -1; // while(cen_root != -1) { // while(!best[cen_root].empty() && !to_remove[cen_root].empty() && // to_remove[cen_root].top() == best[cen_root].top()) { // to_remove[cen_root].pop(); // best[cen_root].pop(); // } // if(!best[cen_root].empty()) { // int cand = best[cen_root].top().second; // int d = tr.dist(u, cand); // if(ans_dist == -1 || d < ans_dist) { // ans_dist = d; // ans_node = cand; // } // } // cen_root = cd.link[cen_root]; // } // assert(ans_node != -1); // return ans_node; // }; // function activate = [&](int u) { // int cen_root = u; // while(cen_root != -1) { // int d = tr.dist(u, cen_root); // best[cen_root].push({-d, u}); // cen_root = cd.link[cen_root]; // } // }; // function deactivate = [&](int u) { // int cen_root = u; // while(cen_root != -1) { // int d = tr.dist(u, cen_root); // to_remove[cen_root].push({-d, u}); // cen_root = cd.link[cen_root]; // } // }; ================================================ FILE: tree/euler_order_segment_tree.cpp ================================================ #include using namespace std; template int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; } template int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; } const int MAXN = (1 << 20); const int inf = (int)1e9 + 42; int n; vector adj[MAXN]; void read() { cin >> n; for(int i = 0; i < n - 1; i++) { int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); } } int st[MAXN], en[MAXN], ver[MAXN], dep[MAXN], dfs_time = 0; vector> dat; void pre_dfs(int u, int pr, int d = 0) { en[u] = st[u] = dfs_time++; ver[st[u]] = u; dep[u] = d; dat.push_back({dep[u]}); for(int v: adj[u]) { if(v != pr) { pre_dfs(v, u, d + 1); dat.push_back({dep[u]}); en[u] = dfs_time++; ver[en[u]] = u; } } } struct segment_tree { struct node { int l, m, r, lm, mr, lmr; node() { l = m = r = lm = mr = lmr = -inf; } node(int d) { l = d; m = -2 * d; r = d; lm = -d; mr = -d; lmr = 0; } }; node merge(node a, node b) { node ret; ret.l = max(a.l, b.l); ret.m = max(a.m, b.m); ret.r = max(a.r, b.r); ret.lm = max(a.lm, b.lm); ret.mr = max(a.mr, b.mr); ret.lmr = max(a.lmr, b.lmr); chkmax(ret.lm, a.l + b.m); chkmax(ret.mr, a.m + b.r); chkmax(ret.lmr, a.lm + b.r); chkmax(ret.lmr, a.l + b.mr); return ret; } int lazy[4 * MAXN]; node tr[4 * MAXN]; void push(int l, int r, int idx) { if(lazy[idx]) { if(l != r) { lazy[2 * idx + 1] ^= lazy[idx]; lazy[2 * idx + 2] ^= lazy[idx]; } lazy[idx] = 0; } } void init(int l, int r, int idx, const vector> &dat) { if(l == r) { tr[idx] = node(dat[l][0]); return; } int mid = (l + r) >> 1; init(l, mid, 2 * idx + 1, dat); init(mid + 1, r, 2 * idx + 2, dat); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int pos, int l, int r, int idx) { if(l == r) { // DO SOMETHING return; } int mid = (l + r) >> 1; if(pos <= mid) { update(pos, l, mid, 2 * idx + 1); } else { update(pos, mid + 1, r, 2 * idx + 2); } tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } void update(int ql, int qr, int l, int r, int idx) { push(l, r, idx); if(ql > r || l > qr) { return; } if(ql <= l && r <= qr) { // DO SOMETHING push(l, r, idx); return; } int mid = (l + r) >> 1; update(ql, qr, l, mid, 2 * idx + 1); update(ql, qr, mid + 1, r, 2 * idx + 2); tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]); } } T; void solve() { pre_dfs(1, 1, 0); T.init(0, (int)dat.size() - 1, 0, dat); } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); read(); solve(); return 0; } ================================================ FILE: tree/lca.hpp ================================================ #include using namespace std; class LCAUtils { protected: int max_log, dfs_time; vector> par_up; void dfs_lca(int u, int pr, int& dfs_time) { in_time[u] = ++dfs_time; par_up[u][0] = pr; for(int i = 1; i < max_log; i++) { par_up[u][i] = par_up[par_up[u][i - 1]][i - 1]; } for(int v: adj[u]) { if(v != pr) { dfs_lca(v, u, dfs_time); } } out_time[u] = ++dfs_time; } public: int n; vector in_time, out_time; vector> adj; LCAUtils() : n(0) {} LCAUtils(int _n) { init(_n); } LCAUtils(int _n, const vector>& _adj, int root = 0) { init(_n); adj = _adj; prepare(root); } void init(int _n) { n = _n; adj.assign(n + 1, {}); } void add_edge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void prepare(int root = 1) { max_log = 1; while((1 << max_log) <= n) { max_log++; } par_up.assign(n + 1, vector(max_log)); in_time.resize(n + 1); out_time.resize(n + 1); dfs_time = 0; dfs_lca(root, root, dfs_time); } int lca(int u, int v) { if(upper(u, v)) { return u; } if(upper(v, u)) { return v; } int a = u; for(int i = max_log - 1; i >= 0; i--) { if(!upper(par_up[a][i], v)) { a = par_up[a][i]; } } return par_up[a][0]; } inline bool upper(int u, int v) { return in_time[u] <= in_time[v] && out_time[v] <= out_time[u]; } }; ================================================ FILE: tree/lca_sparse_table.hpp ================================================ #include #include using namespace std; class LCAUtilsRMQ { private: static pair _min_custom(pair a, pair b) { return min(a, b); } SparseTable, _min_custom> rmq; vector pos, dep; vector> order; void pre_dfs(int u, int pr = -1, int d = 0) { pos[u] = order.size(); dep[u] = d; order.push_back({d, u}); for(int v: adj[u]) { if(v != pr) { pre_dfs(v, u, d + 1); order.push_back({d, u}); } } } public: int n; vector> adj; LCAUtilsRMQ() { n = 0; } LCAUtilsRMQ(int _n) { init(_n); } LCAUtilsRMQ(int _n, const vector>& _adj) { init(_n); adj = _adj; } void add_edge(int u, int v) { adj[u].push_back(v); adj[v].push_back(u); } void init(int _n) { n = _n; order.clear(); adj.assign(n, {}); } void prepare(int root = 0) { order.clear(); pos.resize(n); dep.resize(n); pre_dfs(root); rmq.init(order); } int lca(int u, int v) { if(pos[u] > pos[v]) { swap(u, v); } return rmq.query(pos[u], pos[v]).second; } int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; } }; using LcaUtils = LCAUtilsRMQ; ================================================ FILE: tree/line_tree.hpp ================================================ #include #include #include using namespace std; class LineTree { private: vector> adj; LCAUtilsRMQ helper_lca; vector vals; DSU uf; vector best_node; public: LineTree() {} LineTree( vector> _adj, vector _vals, bool one_indexed = true ) { init(_adj, _vals, one_indexed); } void init( vector> _adj, vector _vals, bool one_indexed = true ) { adj = _adj; vals = _vals; int n = (int)vals.size() - (int)one_indexed; helper_lca.init(n); uf.init(n); vector perm(n); iota(perm.begin(), perm.end(), (int)one_indexed); sort(perm.begin(), perm.end(), [&](int u, int v) { return pair{vals[u], u} > pair{vals[v], v}; }); best_node.resize(n + 1); for(int i = 1; i <= n; i++) { best_node[i] = i; } for(int u: perm) { for(int v: adj[u]) { if(pair{vals[v], v} > pair{vals[u], u}) { helper_lca.add_edge(u, best_node[uf.root(v)]); uf.unite(u, v); } } best_node[uf.root(u)] = u; } helper_lca.prepare(perm.back()); } int min_value(int u, int v) { return vals[helper_lca.lca(u, v)]; } int min_node(int u, int v) { return helper_lca.lca(u, v); } }; ================================================ FILE: tree/link_cut_tree.hpp ================================================ #include using namespace std; // Mine was slow, so based it on maspy's implementation: // https://codeforces.com/contest/2097/submission/317301108 template< class T, T (*merge)(T, T), T (*e)(), T (*inverse)(T), class G, T (*lazy_apply)(G, T), G (*lazy_merge)(G, G), G (*lazy_init)(T)> class LinkCutTree { private: const G lazy_e = lazy_init(e()); struct Node { Node *left, *right, *par; T value; // Node value T path_agg; // Path aggregate T subtree_agg; // Subtree aggregate G lazy; // Lazy propagation value bool flip; // Reverse tag int idx; // Node index Node(T val = e(), int id = -1) : left(nullptr), right(nullptr), par(nullptr), value(val), path_agg(val), lazy(lazy_init(e())), flip(false), idx(id) {} }; vector nodes; void push(Node* x) { if(!x) { return; } if(x->flip) { swap(x->left, x->right); if(x->left) { x->left->flip = !x->left->flip; } if(x->right) { x->right->flip = !x->right->flip; } x->flip = false; } if(x->lazy != lazy_e) { x->value = lazy_apply(x->lazy, x->value); x->path_agg = lazy_apply(x->lazy, x->path_agg); if(x->left) { x->left->lazy = lazy_merge(x->left->lazy, x->lazy); } if(x->right) { x->right->lazy = lazy_merge(x->right->lazy, x->lazy); } x->lazy = lazy_e; } } void pull(Node* x) { if(!x) { return; } push(x->left); push(x->right); x->path_agg = e(); if(x->left) { x->path_agg = merge(x->left->path_agg, x->path_agg); } x->path_agg = merge(x->path_agg, x->value); if(x->right) { x->path_agg = merge(x->path_agg, x->right->path_agg); } } inline int state(Node* n) { if(!n->par) { return 0; } if(n->par->left == n) { return 1; } if(n->par->right == n) { return -1; } return 0; } bool is_root(Node* x) { return state(x) == 0; } void rotate(Node* x) { Node *p = x->par, *pp = p->par; if(p->left == x) { p->left = x->right; if(x->right) { x->right->par = p; } x->right = p; } else { p->right = x->left; if(x->left) { x->left->par = p; } x->left = p; } p->par = x; x->par = pp; if(pp) { if(pp->left == p) { pp->left = x; } else if(pp->right == p) { pp->right = x; } else { change_light(pp, p, x); } } pull(p); pull(x); } void splay(Node* x) { push(x); while(!is_root(x)) { Node *p = x->par, *pp = p->par; if(is_root(p)) { push(p); push(x); rotate(x); } else { push(pp); push(p); push(x); if(state(x) == state(p)) { rotate(p); rotate(x); } else { rotate(x); rotate(x); } } } } Node* expose(Node* x) { Node* rp = nullptr; for(Node* c = x; c; c = c->par) { splay(c); if(c->right) { add_light(c, c->right); } c->right = rp; if(rp) { erase_light(c, rp); } pull(c); rp = c; } splay(x); return rp; } void apply_lazy_to_node(Node* node, const G& lazy_val) { if(!node) { return; } node->lazy = lazy_merge(node->lazy, lazy_val); push(node); } void add_light(Node* c, Node* light) { c->subtree_agg = merge(c->subtree_agg, light->path_agg); } void erase_light(Node* c, Node* light) { c->subtree_agg = merge(c->subtree_agg, inverse(light->path_agg)); } public: LinkCutTree(int n) : nodes(n) { for(int i = 0; i < n; i++) { nodes[i] = Node(e(), i); } } LinkCutTree(const vector& values) : nodes(values.size()) { for(int i = 0; i < values.size(); i++) { nodes[i] = Node(values[i], i); } } Node* access(int x) { Node* u = &nodes[x]; expose(u); return u; } void reroot(int x) { access(x); nodes[x].flip = !nodes[x].flip; push(&nodes[x]); } void link(int u, int v) { reroot(u); access(v); assert(!nodes[u].par && !nodes[v].right); nodes[u].par = &nodes[v]; nodes[v].right = &nodes[u]; pull(&nodes[v]); } void cut(int u, int v) { reroot(u); access(v); assert(!nodes[v].par && nodes[v].left == &nodes[u]); nodes[v].left->par = nullptr; nodes[v].left = nullptr; pull(&nodes[v]); } bool connected(int u, int v) { if(u == v) { return true; } access(u); access(v); return nodes[u].par != nullptr; } int lca(int u, int v) { if(u == v) { return u; } access(u); Node* ancestor = expose(&nodes[v]); return nodes[u].par ? ancestor->idx : -1; } T path_query(int u, int v) { reroot(u); access(v); return nodes[v].path_agg; } void update(int u, const T& val) { access(u); nodes[u].value = val; pull(&nodes[u]); } void path_update(int u, int v, const G& lazy_val) { reroot(u); access(v); apply_lazy_to_node(&nodes[v], lazy_val); } T get(int u) { access(u); return nodes[u].value; } int get_root(int u) { access(u); Node* c = &nodes[u]; push(c); while(c->left) { c = c->left; push(c); } splay(c); return c->idx; } int jump(int u, int v, int k) { reroot(v); access(u); assert(0 <= k && k < nodes[u].size); Node* c = &nodes[u]; while(true) { push(c); int rs = c->right ? c->right->size : 0; if(k < rs) { c = c->right; continue; } if(k == rs) { break; } k -= (rs + 1); c = c->left; } splay(c); return c->idx; } Node* get_node(int idx) { return &nodes[idx]; } int size() const { return nodes.size(); } // Overload this for more complicated updates: void change_light(Node* pp, Node* p, Node* x) { // noop by default. } // Useful for debugging. void print_node(Node* node, int indent = 0) { cout << string(indent, ' ') << string(16, '-') << '\n'; cout << string(indent, ' ') << "Node " << node->idx << ": "; cout << string(indent, ' ') << "Value: " << node->value << '\n'; cout << string(indent, ' ') << "Path agg: " << node->path_agg << '\n'; cout << string(indent, ' ') << "Subtree agg: " << node->subtree_agg << '\n'; cout << string(indent, ' ') << "Virtual agg: " << node->virtual_agg << '\n'; cout << string(indent, ' ') << "Lazy: " << node->lazy.add_val << '\n'; cout << string(indent, ' ') << "HAS PARENT: " << (node->par ? to_string(node->par->idx) : "null") << '\n'; cout << string(indent, ' ') << string(16, '-') << '\n'; } void print_tree(Node* node, int indent = 0) { print_node(node, indent); push(node); if(node->ch[0]) { cout << string(indent, ' ') << "Left child:\n"; print_tree(node->ch[0], indent + 2); } if(node->ch[1]) { cout << string(indent, ' ') << "Right child:\n"; print_tree(node->ch[1], indent + 2); } pull(node); } }; ================================================ FILE: tree/vertex_add_path_sum.hpp ================================================ #include #include "coding_library/data_structures/fenwick_range_update.hpp" #include "coding_library/tree/lca.hpp" using namespace std; class VertexAddPathSum : LCAUtils { private: FenwickRangeUpdate ft; public: VertexAddPathSum() {} void prepare(int root = 1) { LCAUtils::prepare(root); ft.init(dfs_time); } int query(int u, int v) { int l = lca(u, v); int ans = ft.query(in_time[u]) + ft.query(in_time[v]) - ft.query(in_time[l]); if(par_up[l][0] != l) { ans -= ft.query(in_time[par_up[l][0]]); } return ans; } void update(int u, int x) { ft.update(in_time[u], out_time[u], x); } }; ================================================ FILE: tree/virtual_tree.hpp ================================================ #include #include using namespace std; class VirtualTree : public LCAUtils { public: VirtualTree() : LCAUtils() {} VirtualTree(int n) : LCAUtils(n) {} VirtualTree(int n, const vector>& adj, int root = 0) : LCAUtils(n, adj, root) { prepare(root); } void add_edge(int u, int v) { LCAUtils::add_edge(u, v); } pair>, vector> build(const vector& vertices) { if(vertices.empty()) { return {{}, {}}; } vector vec = vertices; sort(vec.begin(), vec.end(), [&](int u, int v) { return in_time[u] < in_time[v]; }); vec.erase(unique(vec.begin(), vec.end()), vec.end()); for(int i = (int)vec.size() - 1; i > 0; i--) { vec.push_back(lca(vec[i - 1], vec[i])); } sort(vec.begin(), vec.end(), [&](int u, int v) { return in_time[u] < in_time[v]; }); vec.erase(unique(vec.begin(), vec.end()), vec.end()); vector> virtual_adj(vec.size()); stack s; s.push(0); for(int i = 1; i < (int)vec.size(); i++) { while(!upper(vec[s.top()], vec[i])) { int u = s.top(); s.pop(); int v = s.top(); virtual_adj[v].push_back(u); } s.push(i); } while(s.size() > 1) { int u = s.top(); s.pop(); int v = s.top(); virtual_adj[v].push_back(u); } return {virtual_adj, vec}; } };