[
  {
    "path": "README.md",
    "content": "# Coding-Library\n\nThis 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. \n\nThe 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.\n\n\n# Random\n\nUseful ideas, that aren't exactly a part of this library.\n\n1) Bitset for almost arbitrary N:\n- https://codeforces.com/blog/entry/100910?#comment-896093\n- https://codeforces.com/problemsets/acmsguru/problem/99999/415\n\n2) MiniSat based SAT solver that can be used in competitive programming:\n- https://github.com/togatoga/togasat?tab=readme-ov-file\n"
  },
  {
    "path": "data_structures/clever_adding_intervals_set.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nstruct clever_set {\n    map<pair<int, int>, T> value;\n\n    void init(int n) { value[{n, 1}] = (T)0; }\n\n    vector<pair<pair<int, int>, T> > add(int l, int r, T val) {\n        auto bg = value.lower_bound({l, 0})->first;\n        if(bg.second != l) {\n            T val = value[bg];\n            value.erase(bg);\n            value[{l - 1, bg.second}] = val;\n            value[{bg.first, l}] = val;\n        }\n\n        auto en = value.lower_bound({r, 0})->first;\n        if(en.first != r) {\n            T val = value[en];\n            value.erase(en);\n            value[{en.first, r + 1}] = val;\n            value[{r, en.second}] = val;\n        }\n\n        vector<pair<pair<int, int>, T> > ret;\n        auto itt = value.lower_bound({l, 0});\n        while(true) {\n            if(itt == value.end() || itt->first.first > r) {\n                break;\n            }\n            ret.push_back({{itt->first.second, itt->first.first}, itt->second});\n            ++itt;\n        }\n\n        for(auto it: ret) {\n            value.erase({it.first.second, it.first.first});\n        }\n\n        value[{r, l}] = val;\n        return ret;\n    }\n};\n"
  },
  {
    "path": "data_structures/compressed_fenwick.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/data_structures/fenwick.hpp>\nusing namespace std;\n\ntemplate<class T>\nstruct CompressedFenwick {\n    Fenwick<T> t;\n    vector<int> li;\n\n    int get_idx(int x) {\n        return lower_bound(li.begin(), li.end(), x) - li.begin() + 1;\n    }\n    void update(int x, T val) { t.update(get_idx(x), val); }\n\n    void add_to_prep(int x) { li.push_back(x); }\n    void prepare() {\n        sort(li.begin(), li.end());\n        li.erase(unique(li.begin(), li.end()), li.end());\n        t.init(li.size() + 2);\n    }\n\n    T query(int x) { return t.query(get_idx(x) - 1); }\n    T size() { return t.query(t.sz); }\n};\n"
  },
  {
    "path": "data_structures/decremental_constant_set.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/graph/dsu.hpp>\nusing namespace std;\n\n/*\nThe structures resembles a set on N positions that are said to initially be\nactive, and supports the following updates:\n- Remove some active position from the set.\n- query_left(i) to find the first active position before i (inclusive). \n- query_right(i) to find the first active position after i (inclusive).\n\nMain idea is to do DSU on blocks of size w=64 working in O(N alpha(N) / w) =\nO(N) overall, and then answer small queries in O(1) using bitwise operations.\n\nBased on Nachia's implementation:\nhttps://codeforces.com/contest/2018/submission/283309295\n*/\n\nclass DecrementalConstantSet {\n  private:\n    const uint64_t FULL_MASK = ~0ull;\n\n    int n, b;\n    vector<uint64_t> mask;\n    vector<int> large_block_left, large_block_right;\n    DSU dsu;\n\n    int small_query_prefix(int c, uint64_t filter_mask) {\n        uint64_t z = mask[c] & filter_mask;\n        return z ? (c << 6) + __builtin_ctzll(z) : -1;\n    }\n\n    int small_query_suffix(int c, uint64_t filter_mask) {\n        uint64_t z = mask[c] & filter_mask;\n        return z ? (c << 6) + 63 - __builtin_clzll(z) : -1;\n    }\n\n  public:\n    DecrementalConstantSet(int _n)\n        : n(_n + 2),\n          b((n + 64) >> 6),\n          mask(b, FULL_MASK),\n          large_block_left(b + 1),\n          large_block_right(b + 1),\n          dsu(b) {\n        iota(large_block_left.begin(), large_block_left.end(), 0);\n        iota(large_block_right.begin(), large_block_right.end(), 0);\n    }\n\n    void remove(int _i) {\n        // Indices are +1\n        int i = _i + 1;\n        int c = i >> 6, d = i & 63;\n        mask[c] &= ~(1ull << d);\n        if(mask[c] == 0) {\n            for(int dir: {-1, 1}) {\n                if(c + dir < 0 || c + dir >= b || mask[c + dir]) {\n                    continue;\n                }\n                int root = dsu.root(c);\n                int next_root = dsu.root(c + dir);\n                if(root != next_root) {\n                    int new_root = dsu.unite(root, next_root);\n                    large_block_left[new_root] =\n                        min(large_block_left[root],\n                            large_block_left[next_root]);\n                    large_block_right[new_root] =\n                        max(large_block_right[root],\n                            large_block_right[next_root]);\n                }\n            }\n        }\n    }\n\n    int query_right(int _i) {\n        if(_i >= n) {\n            return n;\n        }\n        // Indices are +1 and we undo when we return\n        int i = max(_i, 0) + 1;\n        int c = i >> 6, d = i & 63;\n        if(d > 0) {\n            int x = small_query_prefix(c, FULL_MASK << d);\n            if(x >= 0) {\n                return x - 1;\n            }\n            c++;\n        }\n\n        if(!mask[c]) {\n            c = large_block_right[dsu.root(c)] + 1;\n        }\n        return small_query_prefix(c, FULL_MASK) - 1;\n    }\n\n    int query_left(int _i) {\n        if(_i < 0) {\n            return -1;\n        }\n        // Indices are +1 and we undo when we return\n        int i = min(_i + 1, n);\n        int c = i >> 6, d = i & 63;\n\n        if(d < 63) {\n            int x = small_query_suffix(c, (1ull << (d + 1)) - 1);\n            if(x >= 0) {\n                return x - 1;\n            }\n            c--;\n        }\n\n        if(!mask[c]) {\n            c = large_block_left[dsu.root(c)] - 1;\n        }\n        return small_query_suffix(c, FULL_MASK) - 1;\n    }\n};\n"
  },
  {
    "path": "data_structures/fenwick.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nclass Fenwick {\n  private:\n    int sz, log_size;\n    vector<T> tr;\n\n  public:\n    void init(int n) {\n        sz = n + 1;\n        log_size = 31 - __builtin_clz(sz);\n        tr.assign(sz + 1, 0);\n    }\n\n    void update(int idx, T val) {\n        if(idx <= 0) {\n            assert(false);\n            return;\n        }\n        for(; idx <= sz; idx += (idx & -idx)) {\n            tr[idx] += val;\n        }\n    }\n\n    T query(int idx) {\n        T ans = 0;\n        for(; idx >= 1; idx -= (idx & -idx)) {\n            ans += tr[idx];\n        }\n\n        return ans;\n    }\n\n    T query(int l, int r) { return query(r) - query(l - 1); }\n\n    int find_kth(T k) {\n        int idx = 0;\n        for(int i = log_size; i >= 0; i--) {\n            if(idx + (1 << i) < sz && tr[idx + (1 << i)] < k) {\n                k -= tr[idx + (1 << i)];\n                idx += (1 << i);\n            }\n        }\n        return idx + 1;\n    }\n};\n"
  },
  {
    "path": "data_structures/fenwick_2d.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, T (*merge)(T, T), T (*identity)()>\nclass Fenwick2d {\n  private:\n    int sz;\n    vector<unordered_map<int, T>> t;\n\n    void update_row(int row, int idx, T val) {\n        if(idx == 0) {\n            return;\n        }\n        for(; idx <= sz; idx += (idx & -idx)) {\n            if(t[row].find(idx) == t[row].end()) {\n                t[row][idx] = merge(identity(), val);\n            } else {\n                t[row][idx] = merge(t[row][idx], val);\n            }\n        }\n    }\n\n    T query_row(int row, int idx) {\n        T ans = identity();\n        for(; idx >= 1; idx -= (idx & -idx)) {\n            if(t[row].find(idx) == t[row].end()) {\n                ans = merge(identity(), ans);\n            } else {\n                ans = merge(t[row][idx], ans);\n            }\n        }\n\n        return ans;\n    }\n\n  public:\n    void init(int _sz) {\n        sz = _sz;\n        t.assign(sz + 1, unordered_map<int, T>());\n    }\n\n    void update(int row, int col, T val) {\n        if(col == 0) {\n            return;\n        }\n        for(; row <= sz; row += (row & -row)) {\n            update_row(row, col, val);\n        }\n    }\n\n    T query(int row, int col) {\n        T ans = identity();\n        for(; row >= 1; row -= (row & -row)) {\n            ans = merge(query_row(row, col), ans);\n        }\n\n        return ans;\n    }\n};\n// int min_custom(int a, int b) { return min(a, b); }\n// int max_custom(int a, int b) { return max(a, b); }\n// int sum_custom(int a, int b) { return a + b; }\n\n// int identity_min() { return INT_MAX; }\n// int identity_max() { return INT_MIN; }\n// int identity_sum() { return 0; }\n\n// Fenwick2d<int, sum_custom, identity_sum> ft;\n"
  },
  {
    "path": "data_structures/fenwick_range_update.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nclass FenwickRangeUpdate { \n  private:\n    int sz;\n    vector<T> tr;\n\n    void update(int idx, T val) {\n        if(idx <= 0) {\n            assert(false);\n            return;\n        }\n        for(; idx <= sz; idx += (idx & -idx)) {\n            tr[idx] += val;\n        }\n    }\n\n  public:\n    void init(int n) {\n        sz = n + 1;\n        tr.assign(sz + 1, 0);\n    }\n\n    T query(int idx) {\n        T ans = 0;\n        for(; idx >= 1; idx -= (idx & -idx)) {\n            ans += tr[idx];\n        }\n\n        return ans;\n    }\n\n    void update(int l, int r, T val) {\n        update(l, val);\n        update(r + 1, -val);\n    }\n};\n"
  },
  {
    "path": "data_structures/fenwick_range_update_range_query.hpp",
    "content": "#include <bits/stdc++.h>\n#include \"coding_library/data_structures/fenwick_range_update.hpp\"\nusing namespace std;\n\ntemplate<class T>\nclass FenwickRangeUpdateRangeQuery {\n    int sz;\n    FenwickRangeUpdate<T> t0, t1;\n\n    void init(int _sz) {\n        sz = _sz;\n        t0.init(sz + 1);\n        t1.init(sz + 1);\n    }\n\n    void update(int l, int r, T val) {\n        t0.update(l, r, val);\n        t1.update(l, r, -(l - 1) * val);\n        t1.update(r + 1, sz, (r - l + 1) * val);\n    }\n\n    T query(int idx) { return t0.query(idx) * (T)idx + t1.query(idx); }\n    T query(int l, int r) { return query(r) - query(l - 1); }\n};\n"
  },
  {
    "path": "data_structures/heap.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, bool (*cmp)(T, T)>\nclass Heap {\n  private:\n    vector<T> heap_values;\n    vector<int> heap, pos_in_heap;\n\n    void push_up(int id) {\n        while(id > 0 &&\n              cmp(heap_values[heap[id]], heap_values[heap[(id - 1) / 2]])) {\n            swap(heap[id], heap[(id - 1) / 2]);\n            swap(pos_in_heap[heap[id]], pos_in_heap[heap[(id - 1) / 2]]);\n            id = (id - 1) / 2;\n        }\n    }\n\n    void push_down(int id) {\n        while(2 * id + 1 < heap.size()) {\n            int child = 2 * id + 1;\n            if(child + 1 < heap.size() &&\n               cmp(heap_values[heap[child + 1]], heap_values[heap[child]])) {\n                child++;\n            }\n            if(cmp(heap_values[heap[id]], heap_values[heap[child]])) {\n                break;\n            }\n            swap(heap[id], heap[child]);\n            swap(pos_in_heap[heap[id]], pos_in_heap[heap[child]]);\n            id = child;\n        }\n    }\n\n  public:\n    Heap() { clear(); }\n\n    void clear() {\n        heap.clear();\n        heap_values.clear();\n        pos_in_heap.clear();\n    }\n\n    int push(T val) {\n        heap.push_back(heap_values.size());\n        pos_in_heap.push_back(heap.size() - 1);\n        heap_values.push_back(val);\n        push_up(heap.size() - 1);\n        return heap_values.size() - 1;\n    }\n\n    T pop() {\n        int ret_node = heap[0];\n        swap(pos_in_heap[ret_node], pos_in_heap[heap.back()]);\n        swap(heap[0], heap[heap.size() - 1]);\n        heap.pop_back();\n        pos_in_heap[ret_node] = -1;\n        if(heap.size() > 0) {\n            push_down(0);\n        }\n        return heap_values[ret_node];\n    }\n\n    size_t size() { return heap.size(); }\n    bool empty() { return heap.size() == 0; }\n\n    T top() { return heap_values[heap[0]]; }\n\n    int top_node() { return heap[0]; }\n\n    void update(int node, T val) {\n        int p = pos_in_heap[node];\n        bool is_push_down = cmp(heap_values[node], val);\n\n        if(is_push_down) {\n            heap_values[node] = val;\n            push_down(p);\n        } else {\n            heap_values[node] = val;\n            push_up(p);\n        }\n    }\n};\n\n"
  },
  {
    "path": "data_structures/meldable_heap.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T = int>\nclass MeldableHeap {\n  private:\n    static uint32_t rng() {\n        static mt19937 static_rng(random_device{}());\n        return static_rng();\n    }\n\n    struct Node {\n        T key;\n        Node *left, *right;\n\n        Node(T _key) : key(_key), left(nullptr), right(nullptr) {}\n    };\n\n    Node* merge(Node* a, Node* b) {\n        if(!a) {\n            return b;\n        }\n        if(!b) {\n            return a;\n        }\n\n        if(a->key > b->key) {\n            swap(a, b);\n        }\n\n        Node* q = new Node(a->key);\n        if(rng() & 1) {\n            q->left = merge(a->left, b);\n            q->right = a->right;\n        } else {\n            q->left = a->left;\n            q->right = merge(a->right, b);\n        }\n\n        return q;\n    }\n\n    pair<Node*, Node*> pop(Node* a) {\n        Node* head = new Node(a->key);\n        Node* tail = merge(a->left, a->right);\n        return {head, tail};\n    }\n\n  public:\n    Node* root;\n\n    MeldableHeap() : root(nullptr) {}\n    MeldableHeap(Node* _root) : root(_root) {}\n\n    MeldableHeap copy() const {\n        MeldableHeap new_heap;\n        new_heap.root = root;\n        return new_heap;\n    }\n\n    MeldableHeap merge(const MeldableHeap<T>& other) {\n        MeldableHeap new_heap;\n        new_heap.root = merge(root, other.root);\n        return new_heap;\n    }\n\n    friend MeldableHeap merge(\n        const MeldableHeap<T>& a, const MeldableHeap<T>& b\n    ) {\n        return a.merge(b);\n    }\n\n    void push(T key) {\n        Node* new_node = new Node(key);\n        root = merge(root, new_node);\n    }\n\n    T pop() {\n        assert(root);\n        auto [head, tail] = pop(root);\n        root = tail;\n        return head->key;\n    }\n\n    T top() const { return root->key; }\n\n    tuple<T, MeldableHeap<T>, MeldableHeap<T>> trio() const {\n        return {\n            root->key, MeldableHeap<T>{root->left}, MeldableHeap<T>{root->right}\n        };\n    }\n\n    bool empty() const { return root == nullptr; }\n\n    bool operator<(const MeldableHeap<T>& other) const {\n        return top() < other.top();\n    }\n};\n"
  },
  {
    "path": "data_structures/merge_sort_tree.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// InnerOrderedSet should implement:\n//     1) insert(x), which adds one copy of x.\n//     2) erase(x), which removes one copy of x.\n//     3) count_leq(x), which gives the number of elements <= x.\n//\n// Example with a treap is given below.\n\ntemplate<class InnerOrderedSet>\nclass MergeSortTree {\n  private:\n    int n;\n    vector<InnerOrderedSet> nodes;\n\n    void update_rec(int v, int tl, int tr, int pos, int y, int delta) {\n        if(delta == 1) {\n            nodes[v].insert(y, 1);\n        } else if(delta == -1) {\n            nodes[v].erase(y);\n        }\n\n        if(tl == tr) {\n            return;\n        }\n        int tm = (tl + tr) / 2;\n        if(pos <= tm) {\n            update_rec(v * 2, tl, tm, pos, y, delta);\n        } else {\n            update_rec(v * 2 + 1, tm + 1, tr, pos, y, delta);\n        }\n    }\n\n    int query_rec(int v, int tl, int tr, int ql, int qr, int k) {\n        if(ql > tr || qr < tl) {\n            return 0;\n        }\n        if(ql <= tl && tr <= qr) {\n            return nodes[v].count_leq(k);\n        }\n        int tm = (tl + tr) / 2;\n        return query_rec(v * 2, tl, tm, ql, qr, k) +\n               query_rec(v * 2 + 1, tm + 1, tr, ql, qr, k);\n    }\n\n  public:\n    void init(int _n) {\n        n = _n;\n        nodes.resize(4 * (n + 10));\n    }\n\n    void update(int x, int y, int delta) { update_rec(1, 1, n, x, y, delta); }\n\n    int query(int qxl, int qxr, int k) {\n        return query_rec(1, 1, n, qxl, qxr, k);\n    }\n\n    int query(int qxl, int qxr, int qyl, int qyr) {\n        return query_rec(1, 1, n, qxl, qxr, qyr) -\n               query_rec(1, 1, n, qxl, qxr, qyl - 1);\n    }\n};\n\n// #include <coding_library/data_structures/treap.hpp>\n// int sum_merge(int a, int b) { return a + b; }\n// using CountTreap = Treap<int, int, sum_merge>;\n// MergeSortTree<CountTreap> st;\n"
  },
  {
    "path": "data_structures/monoids_lazy.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nclass MonoidMin {\n  public:\n    struct MinVal {\n        T val;\n        bool operator==(const MinVal& other) const { return val == other.val; }\n        bool operator!=(const MinVal& other) const { return !(*this == other); }\n    };\n\n    struct AddLazy {\n        T add_val;\n        bool operator==(const AddLazy& other) const {\n            return add_val == other.add_val;\n        }\n        bool operator!=(const AddLazy& other) const {\n            return !(*this == other);\n        }\n    };\n\n    static MinVal merge(MinVal a, MinVal b) { return {min(a.val, b.val)}; }\n\n    static MinVal e() { return {numeric_limits<T>::max()}; }\n\n    static MinVal lazy_apply(AddLazy f, MinVal x) {\n        return {x.val + f.add_val};\n    }\n\n    static AddLazy lazy_merge(AddLazy a, AddLazy b) {\n        return {a.add_val + b.add_val};\n    }\n\n    static AddLazy lazy_init(MinVal _) { return {0}; }\n};\n\n// SegmentTreeLazy<\n//     MonoidMin<int>::MinVal,\n//     MonoidMin<int>::merge,\n//     MonoidMin<int>::e,\n//     MonoidMin<int>::AddLazy,\n//     MonoidMin<int>::lazy_apply,\n//     MonoidMin<int>::lazy_merge,\n//     MonoidMin<int>::lazy_init>\n\ntemplate<class T>\nclass MonoidSum {\n  public:\n    using Sum = T;\n    using AddLazy = T;\n\n    static Sum merge(Sum a, Sum b) { return a + b; }\n\n    static Sum e() { return 0; }\n\n    static Sum lazy_apply(AddLazy f, Sum x) { return f + x; }\n\n    static AddLazy lazy_merge(AddLazy a, AddLazy b) { return a + b; }\n\n    static AddLazy lazy_init(Sum _) { return 0; }\n\n    static Sum inverse(Sum x) { return -x; }\n};\n\n// SegmentTreeLazy<\n//     MonoidSum<int>::Sum,\n//     MonoidSum<int>::merge,\n//     MonoidSum<int>::e,\n//     MonoidSum<int>::AddLazy,\n//     MonoidSum<int>::lazy_apply,\n//     MonoidSum<int>::lazy_merge,\n//     MonoidSum<int>::lazy_init>\n\ntemplate<class T>\nclass MonoidMinWithCount {\n  public:\n    struct MinWithCount {\n        T min_val;\n        int count;\n\n        bool operator==(const MinWithCount& other) const {\n            return min_val == other.min_val && count == other.count;\n        }\n        bool operator!=(const MinWithCount& other) const {\n            return !(*this == other);\n        }\n    };\n\n    struct AddLazy {\n        T add_val;\n        bool operator==(const AddLazy& other) const {\n            return add_val == other.add_val;\n        }\n        bool operator!=(const AddLazy& other) const {\n            return !(*this == other);\n        }\n    };\n\n    static MinWithCount merge(MinWithCount a, MinWithCount b) {\n        if(a.min_val < b.min_val) {\n            return a;\n        }\n        if(b.min_val < a.min_val) {\n            return b;\n        }\n        return {a.min_val, a.count + b.count};\n    }\n\n    static MinWithCount e() { return {numeric_limits<T>::max(), 0}; }\n\n    static MinWithCount lazy_apply(AddLazy f, MinWithCount x) {\n        return {x.min_val + f.add_val, x.count};\n    }\n\n    static AddLazy lazy_merge(AddLazy a, AddLazy b) {\n        return {a.add_val + b.add_val};\n    }\n    static AddLazy lazy_init(MinWithCount _) { return {0}; }\n};\n\n// SegmentTreeLazy<\n//     MonoidMinWithCount<int>::MinWithCount,\n//     MonoidMinWithCount<int>::merge,\n//     MonoidMinWithCount<int>::e,\n//     MonoidMinWithCount<int>::AddLazy,\n//     MonoidMinWithCount<int>::lazy_apply,\n//     MonoidMinWithCount<int>::lazy_merge,\n//     MonoidMinWithCount<int>::lazy_init>\n\ntemplate<class T>\nclass MonoidSumArithmeticProgression {\n    struct Sum {\n        T val;\n        T l, r;\n        bool operator==(const Sum& other) const {\n            return val == other.val && l == other.l && r == other.r;\n        }\n        bool operator!=(const Sum& other) const { return !(*this == other); }\n    };\n    struct AddLazy {\n        T alpha;\n        T beta;\n        T l_border;\n        bool operator==(const AddLazy& other) const {\n            return alpha == other.alpha && beta == other.beta &&\n                   l_border == other.l_border;\n        }\n        bool operator!=(const AddLazy& other) const {\n            return !(*this == other);\n        }\n    };\n\n    static Sum merge(Sum a, Sum b) {\n        return {\n            a.val + b.val,\n            a.l,\n            b.r,\n        };\n    }\n    static Sum e() { return {0, 0}; }\n    static Sum lazy_apply(AddLazy f, Sum x) {\n        T delta = x.l - f.l_border;\n        T len = x.r - x.l + 1;\n        x.val +=\n            (delta * f.beta + f.alpha) * len + f.beta * len * (len + 1) / 2;\n        return x;\n    }\n    static AddLazy lazy_merge(AddLazy a, AddLazy b) {\n        T delta = b.l_border - a.l_border;\n        b.alpha += a.alpha + delta * a.beta;\n        b.beta += a.beta;\n        return b;\n    }\n    static AddLazy lazy_init(Sum node) { return {0, 0, node.l}; }\n};\n\n// SegmentTreeLazy<\n//     MonoidSumArithmeticProgression<int64_t>::Sum,\n//     MonoidSumArithmeticProgression<int64_t>::merge,\n//     MonoidSumArithmeticProgression<int64_t>::e,\n//     MonoidSumArithmeticProgression<int64_t>::AddLazy,\n//     MonoidSumArithmeticProgression<int64_t>::lazy_apply,\n//     MonoidSumArithmeticProgression<int64_t>::lazy_merge,\n//     MonoidSumArithmeticProgression<int64_t>::lazy_init>\n"
  },
  {
    "path": "data_structures/nonintersecting_range_tree.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n/* Based on https://codeforces.com/contest/2063/problem/F2. Main idea is to\n   do reverse small-to-large trick and we can store everything with arrays\n   instead of using a complicated approach with sets and maps.\n\n   This version only counts the \"non-used\" elements in the range, so\n   we might want to redefine this in a different problem.\n*/\n\nclass NonintersectingRangeTree {\n  public:\n    vector<int> pnt, size, par, par_idx;\n    vector<bool> used;\n\n    NonintersectingRangeTree(int n) {\n        pnt.assign(n + 2, 0);\n        iota(pnt.begin(), pnt.end(), 1);\n\n        par_idx.assign(n + 2, 0);\n        par = {0};\n\n        size.assign(n + 2, 0);\n        used.assign(n + 2, false);\n\n        used[0] = true;\n        pnt[0] = n + 2;\n        pnt[n + 1] = n + 1;\n        size[0] = n;\n    }\n\n    void add(int l, int r) {\n        pnt[l] = r + 1;\n        pnt[r] = r;\n        used[l] = true;\n\n        int p = get_parent(l);\n        int out_ptr = p + 1, ins_ptr = l + 1;\n        int out_size = 0, ins_size = 0;\n\n        while(pnt[out_ptr] != out_ptr && pnt[ins_ptr] != ins_ptr) {\n            out_size += !used[out_ptr];\n            ins_size += !used[ins_ptr];\n            out_ptr = pnt[out_ptr];\n            ins_ptr = pnt[ins_ptr];\n        }\n\n        int upd_ptr, new_par_idx = par.size();\n        if(pnt[out_ptr] == out_ptr) {\n            upd_ptr = p + 1;\n            par.push_back(p);\n            par[par_idx[l]] = l;\n\n            ins_size = size[p] - 2 - out_size;\n            size[p] = out_size;\n            size[l] = ins_size;\n        } else {\n            upd_ptr = l + 1;\n            par.push_back(l);\n\n            out_size = size[p] - 2 - ins_size;\n            size[p] = out_size;\n            size[l] = ins_size;\n        }\n\n        while(pnt[upd_ptr] != upd_ptr) {\n            par_idx[upd_ptr] = new_par_idx;\n            upd_ptr = pnt[upd_ptr];\n        }\n    }\n\n    int get_parent(int x) { return par[par_idx[x]]; }\n};\n"
  },
  {
    "path": "data_structures/offline_segment_tree_2d.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/data_structures/fenwick.hpp>\n\nusing namespace std;\n\ntemplate<class T>\nclass OfflineSegmentTree2d {\n  private:\n    int n;\n    vector<vector<int>> ys;\n    vector<Fenwick<T>> ft;\n\n    void collect(int v, int tl, int tr, int pos, int y) {\n        ys[v].push_back(y);\n        if(tl == tr) {\n            return;\n        }\n        int tm = (tl + tr) / 2;\n        if(pos <= tm) {\n            collect(v * 2, tl, tm, pos, y);\n        } else {\n            collect(v * 2 + 1, tm + 1, tr, pos, y);\n        }\n    }\n\n    void build_compression(int v) {\n        sort(ys[v].begin(), ys[v].end());\n        ys[v].erase(unique(ys[v].begin(), ys[v].end()), ys[v].end());\n        ft[v].init(ys[v].size() + 2);\n    }\n\n    void update_rec(int v, int tl, int tr, int pos, int y, T val) {\n        if(ys[v].empty()) {\n            return;\n        }\n        auto it = lower_bound(ys[v].begin(), ys[v].end(), y);\n        if(it == ys[v].end() || *it != y) {\n            return;\n        }\n        int rank = (it - ys[v].begin()) + 1;\n        ft[v].update(rank, val);\n        if(tl == tr) {\n            return;\n        }\n        int tm = (tl + tr) / 2;\n        if(pos <= tm) {\n            update_rec(v * 2, tl, tm, pos, y, val);\n        } else {\n            update_rec(v * 2 + 1, tm + 1, tr, pos, y, val);\n        }\n    }\n\n    T query_rec(int v, int tl, int tr, int l, int r, int yl, int yr) {\n        if(l > tr || r < tl) {\n            return 0;\n        }\n        if(l <= tl && tr <= r) {\n            if(ys[v].empty()) {\n                return 0;\n            }\n            auto itl = lower_bound(ys[v].begin(), ys[v].end(), yl);\n            auto itr = upper_bound(itl, ys[v].end(), yr);\n            int ly = (itl - ys[v].begin()) + 1;\n            int ry = (itr - ys[v].begin());\n            return ft[v].query(ly, ry);\n        }\n        int tm = (tl + tr) / 2;\n        return query_rec(v * 2, tl, tm, l, r, yl, yr) +\n               query_rec(v * 2 + 1, tm + 1, tr, l, r, yl, yr);\n    }\n\n  public:\n    void init(int _n) {\n        n = _n;\n        int tsz = 4 * (n + 10);\n        ys.assign(tsz, {});\n        ft.resize(tsz);\n    }\n\n    void prepare_update(int x, int y) { collect(1, 1, n, x, y); }\n\n    void prepare() {\n        for(int v = 1; v < 4 * (n + 10); ++v) {\n            if(!ys[v].empty()) {\n                build_compression(v);\n            }\n        }\n    }\n\n    void update(int x, int y, T val) { update_rec(1, 1, n, x, y, val); }\n\n    T query(int xl, int xr, int yl, int yr) {\n        return query_rec(1, 1, n, xl, xr, yl, yr);\n    }\n};\n"
  },
  {
    "path": "data_structures/rmq2d.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nstruct rmq1d {\n    vector<int> rmq;\n    int n;\n    void init(int N) {\n        n = N;\n        rmq.resize(4 * n);\n    }\n    void add(int v, int tl, int tr, int x) {\n        ++rmq[v];\n        if(tl + 1 == tr) {\n            return;\n        }\n        int m = (tl + tr) >> 1;\n        if(x < m) {\n            add(v * 2 + 1, tl, m, x);\n        } else {\n            add(v * 2 + 2, m, tr, x);\n        }\n    }\n    void add(int x) { add(0, 0, n, x); }\n    int get(int v, int tl, int tr, int l, int r) {\n        if(r <= tl || tr <= l) {\n            return 0;\n        }\n        if(l <= tl && tr <= r) {\n            return rmq[v];\n        }\n        int m = (tl + tr) >> 1;\n        return get(v * 2 + 1, tl, m, l, r) + get(v * 2 + 2, m, tr, l, r);\n    }\n    int get(int l, int r) { return get(0, 0, n, l, r); }\n};\n\nstruct rmq2d {\n    vector<rmq1d> rmq;\n    vector<vector<int> > sv;\n    int n;\n    void init(int N) {\n        n = N;\n        sv.resize(4 * n);\n        rmq.resize(4 * n);\n    }\n    void prep(int v, int tl, int tr, int x, int y) {\n        sv[v].push_back(y);\n        if(tl + 1 == tr) {\n            return;\n        }\n        int m = (tl + tr) >> 1;\n        if(x < m) {\n            prep(v * 2 + 1, tl, m, x, y);\n        } else {\n            prep(v * 2 + 2, m, tr, x, y);\n        }\n    }\n    void prep(int x, int y) { prep(0, 0, n, x, y); }\n    void add(int v, int tl, int tr, int x, int y) {\n        int k = lower_bound(sv[v].begin(), sv[v].end(), y) - sv[v].begin();\n        rmq[v].add(k);\n        if(tl + 1 == tr) {\n            return;\n        }\n        int m = (tl + tr) >> 1;\n        if(x < m) {\n            add(v * 2 + 1, tl, m, x, y);\n        } else {\n            add(v * 2 + 2, m, tr, x, y);\n        }\n    }\n    void add(int x, int y) { add(0, 0, n, x, y); }\n    void build(int v, int tl, int tr) {\n        sort(sv[v].begin(), sv[v].end());\n        rmq[v].init(sv[v].size());\n        if(tl + 1 == tr) {\n            return;\n        }\n        int m = (tl + tr) >> 1;\n        build(v * 2 + 1, tl, m);\n        build(v * 2 + 2, m, tr);\n    }\n    void init2() { build(0, 0, n); }\n    int get(int v, int tl, int tr, int l1, int r1, int l2, int r2) {\n        if(r1 <= tl || tr <= l1) {\n            return 0;\n        }\n        if(l1 <= tl && tr <= r1) {\n            l2 = lower_bound(sv[v].begin(), sv[v].end(), l2) - sv[v].begin();\n            r2 = lower_bound(sv[v].begin(), sv[v].end(), r2) - sv[v].begin();\n            return rmq[v].get(l2, r2);\n        }\n        int m = (tl + tr) >> 1;\n        return get(v * 2 + 1, tl, m, l1, r1, l2, r2) +\n               get(v * 2 + 2, m, tr, l1, r1, l2, r2);\n    }\n    int get(int l1, int r1, int l2, int r2) {\n        return get(0, 0, n, l1, r1, l2, r2);\n    }\n};\n"
  },
  {
    "path": "data_structures/segment_tree.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Motivated by atcoder library, but adapted to my style. All ranges are\n// inclusive in this implementation.\n// https://atcoder.github.io/ac-library/production/document_en/segtree.html\n\ntemplate<class T, T (*merge)(T, T), T (*e)()>\nclass SegmentTree {\n  private:\n    int n, size;\n    vector<T> tr;\n\n    void pull(int x) { tr[x] = merge(tr[2 * x], tr[2 * x + 1]); }\n\n  public:\n    SegmentTree() { init(vector<T>()); }\n    SegmentTree(int _n) { init(vector<T>(_n, e())); }\n    SegmentTree(const vector<T>& _a) { init(_a); }\n\n    void init(const vector<T>& _a) {\n        n = _a.size();\n        size = 1;\n        while(size < n) {\n            size <<= 1;\n        }\n\n        tr.assign(2 * size, e());\n        for(int i = 0; i < n; i++) {\n            tr[size + i] = _a[i];\n        }\n        for(int i = size - 1; i > 0; i--) {\n            pull(i);\n        }\n    }\n\n    void update(int pos, T val) {\n        pos += size;\n        tr[pos] = val;\n        for(pos >>= 1; pos > 0; pos >>= 1) {\n            pull(pos);\n        }\n    }\n\n    T get_pos(int pos) { return tr[pos + size]; }\n\n    T query(int l, int r) {\n        T ansl = e(), ansr = e();\n        for(l += size, r += size + 1; l < r; l >>= 1, r >>= 1) {\n            if(l & 1) {\n                ansl = merge(ansl, tr[l++]);\n            }\n            if(r & 1) {\n                ansr = merge(tr[--r], ansr);\n            }\n        }\n        return merge(ansl, ansr);\n    }\n\n    T query_all() { return tr[1]; }\n\n    template<bool (*f)(T)>\n    int max_right(int l) const {\n        return max_right(l, [](T x) { return f(x); });\n    }\n    template<class F>\n    int max_right(int l, F f) const {\n        if(l == n) {\n            return n;\n        }\n\n        l += size;\n        T sm = e();\n        do {\n            while(l % 2 == 0) {\n                l >>= 1;\n            }\n            if(!f(merge(sm, tr[l]))) {\n                while(l < size) {\n                    l = (2 * l);\n                    if(f(merge(sm, tr[l]))) {\n                        sm = merge(sm, tr[l]);\n                        l++;\n                    }\n                }\n                return l - size;\n            }\n            sm = merge(sm, tr[l]);\n            l++;\n        } while((l & -l) != l);\n        return n;\n    }\n\n    template<bool (*f)(T)>\n    int min_left(int r) const {\n        return min_left(r, [](T x) { return f(x); });\n    }\n    template<class F>\n    int min_left(int r, F f) const {\n        if(r == -1) {\n            return 0;\n        }\n\n        r += size + 1;\n        T sm = e();\n        do {\n            r--;\n            while(r > 1 && (r % 2)) {\n                r >>= 1;\n            }\n            if(!f(merge(tr[r], sm))) {\n                while(r < size) {\n                    r = (2 * r + 1);\n                    if(f(merge(tr[r], sm))) {\n                        sm = merge(tr[r], sm);\n                        r--;\n                    }\n                }\n                return r + 1 - size;\n            }\n            sm = merge(tr[r], sm);\n        } while((r & -r) != r);\n        return 0;\n    }\n};\n\n// int min_custom(int a, int b) { return min(a, b); }\n// int min_e() { return INT_MAX; }\n// int max_custom(int a, int b) { return max(a, b); }\n// int max_e() { return INT_MIN; }\n"
  },
  {
    "path": "data_structures/segment_tree_lazy.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Motivated by atcoder library, but adapted to my style. All ranges are\n// inclusive in this implementation.\n// https://atcoder.github.io/ac-library/production/document_en/segtree.html\n//\n// Another difference is that I support a callback from the tree node to\n// the lazy node, which is useful when we want to maintain a push that is\n// not uniform across the left and right child (arithmetic progression add).\n\ntemplate<\n    class T, T (*merge)(T, T), T (*e)(), class G, T (*lazy_apply)(G, T),\n    G (*lazy_merge)(G, G), G (*lazy_init)(T)>\nclass SegmentTreeLazy {\n  private:\n    int n, size, log_size;\n    vector<T> tr;\n    vector<G> lazy;\n\n    void pull(int x) { tr[x] = merge(tr[2 * x], tr[2 * x + 1]); }\n\n    void push_one(int x, G f) {\n        tr[x] = lazy_apply(f, tr[x]);\n        if(x < size) {\n            lazy[x] = lazy_merge(f, lazy[x]);\n        }\n    }\n\n    void push(int x) {\n        push_one(2 * x, lazy[x]);\n        push_one(2 * x + 1, lazy[x]);\n        lazy[x] = lazy_init(tr[x]);\n    }\n\n    void push_all_down(int x) {\n        for(int i = log_size; i >= 1; i--) {\n            push(x >> i);\n        }\n    }\n\n    void push_all_open_range(int l, int r) {\n        for(int i = log_size; i >= 1; i--) {\n            if(((l >> i) << i) != l) {\n                push(l >> i);\n            }\n            if(((r >> i) << i) != r) {\n                push((r - 1) >> i);\n            }\n        }\n    }\n\n  public:\n    SegmentTreeLazy() { init(vector<T>()); }\n    SegmentTreeLazy(int _n) { init(vector<T>(_n, e())); }\n    SegmentTreeLazy(const vector<T> &_a) { init(_a); }\n\n    void init(const vector<T> &_a) {\n        n = _a.size();\n        size = 1;\n        log_size = 0;\n        while(size < n) {\n            size <<= 1;\n            log_size++;\n        }\n\n        tr.assign(2 * size, e());\n        lazy.resize(size);\n        for(int i = 0; i < n; i++) {\n            tr[size + i] = _a[i];\n        }\n        for(int i = size - 1; i > 0; i--) {\n            pull(i);\n            lazy[i] = lazy_init(tr[i]);\n        }\n    }\n\n    void update(int pos, T val) {\n        pos += size;\n        push_all_down(pos);\n        tr[pos] = val;\n        for(pos >>= 1; pos > 0; pos >>= 1) {\n            pull(pos);\n        }\n    }\n\n    void apply_lazy(int l, int r, G f) {\n        if(l > r) {\n            return;\n        }\n\n        l += size, r += size + 1;\n        push_all_open_range(l, r);\n        for(int l0 = l, r0 = r; l0 < r0; l0 >>= 1, r0 >>= 1) {\n            if(l0 & 1) {\n                push_one(l0++, f);\n            }\n            if(r0 & 1) {\n                push_one(--r0, f);\n            }\n        }\n\n        for(int i = 1; i <= log_size; i++) {\n            if(((l >> i) << i) != l) {\n                pull(l >> i);\n            }\n            if(((r >> i) << i) != r) {\n                pull((r - 1) >> i);\n            }\n        }\n    }\n\n    T get_pos(int pos) {\n        pos += size;\n        push_all_down(pos);\n        return tr[pos];\n    }\n\n    T query(int l, int r) {\n        T ansl = e(), ansr = e();\n        l += size, r += size + 1;\n        push_all_open_range(l, r);\n\n        for(; l < r; l >>= 1, r >>= 1) {\n            if(l & 1) {\n                ansl = merge(ansl, tr[l++]);\n            }\n            if(r & 1) {\n                ansr = merge(tr[--r], ansr);\n            }\n        }\n        return merge(ansl, ansr);\n    }\n\n    T query_all() { return tr[1]; }\n\n    template<bool (*f)(T)>\n    int max_right(int l) const {\n        return max_right(l, [](T x) { return f(x); });\n    }\n    template<class F>\n    int max_right(int l, F f) const {\n        if(l == n) {\n            return n;\n        }\n\n        l += size;\n        push_all_down(l);\n        T sm = e();\n        do {\n            while(l % 2 == 0) {\n                l >>= 1;\n            }\n            if(!f(merge(sm, tr[l]))) {\n                while(l < size) {\n                    push(l);\n                    l = (2 * l);\n                    if(f(merge(sm, tr[l]))) {\n                        sm = merge(sm, tr[l]);\n                        l++;\n                    }\n                }\n                return l - size;\n            }\n            sm = merge(sm, tr[l]);\n            l++;\n        } while((l & -l) != l);\n        return n;\n    }\n\n    template<bool (*f)(T)>\n    int min_left(int r) const {\n        return min_left(r, [](T x) { return f(x); });\n    }\n    template<class F>\n    int min_left(int r, F f) const {\n        if(r == -1) {\n            return 0;\n        }\n\n        r += size + 1;\n        push_all_down(r - 1);\n        T sm = e();\n        do {\n            r--;\n            while(r > 1 && (r % 2)) {\n                r >>= 1;\n            }\n            if(!f(merge(tr[r], sm))) {\n                while(r < size) {\n                    push(r);\n                    r = (2 * r + 1);\n                    if(f(merge(tr[r], sm))) {\n                        sm = merge(tr[r], sm);\n                        r--;\n                    }\n                }\n                return r + 1 - size;\n            }\n            sm = merge(tr[r], sm);\n        } while((r & -r) != r);\n        return 0;\n    }\n};\n"
  },
  {
    "path": "data_structures/set_lazy.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<typename T, template<typename...> class Container = multiset>\nclass SetLazy : private Container<T> {\n  private:\n    T lazy_value = T();\n\n    class Iterator {\n      private:\n        typename Container<T>::iterator it;\n        const T& lazy_value;\n\n      public:\n        Iterator(typename Container<T>::iterator it, const T& lazy_value)\n            : it(it), lazy_value(lazy_value) {}\n\n        T operator*() const { return *it + lazy_value; }\n        Iterator& operator++() {\n            ++it;\n            return *this;\n        }\n        Iterator operator++(int) {\n            Iterator tmp = *this;\n            ++it;\n            return tmp;\n        }\n        bool operator==(const Iterator& other) const { return it == other.it; }\n        bool operator!=(const Iterator& other) const { return it != other.it; }\n\n        typename Container<T>::iterator base() const { return it; }\n    };\n\n  public:\n    void insert(const T& value) { Container<T>::insert(value - lazy_value); }\n\n    void erase(const T& value) { Container<T>::erase(value - lazy_value); }\n    void erase(Iterator it) { Container<T>::erase(it.base()); }\n\n    void add_all(const T& x) { lazy_value += x; }\n\n    T get_lazy_value() const { return lazy_value; }\n\n    bool count(const T& value) const {\n        return Container<T>::find(value - lazy_value) != Container<T>::end();\n    }\n\n    Iterator find(const T& value) {\n        auto it = Container<T>::find(value - lazy_value);\n        return it != Container<T>::end() ? Iterator(it, lazy_value) : end();\n    }\n\n    Iterator lower_bound(const T& value) {\n        return Iterator(\n            Container<T>::lower_bound(value - lazy_value), lazy_value\n        );\n    }\n\n    Iterator upper_bound(const T& value) {\n        return Iterator(\n            Container<T>::upper_bound(value - lazy_value), lazy_value\n        );\n    }\n\n    Iterator begin() { return Iterator(Container<T>::begin(), lazy_value); }\n    Iterator end() { return Iterator(Container<T>::end(), lazy_value); }\n\n    const Iterator begin() const {\n        return Iterator(Container<T>::begin(), lazy_value);\n    }\n    const Iterator end() const {\n        return Iterator(Container<T>::end(), lazy_value);\n    }\n\n    using Container<T>::size;\n    using Container<T>::empty;\n\n    void merge(const SetLazy<T, Container>& other) {\n        for(const auto& value: other) {\n            insert(value);\n        }\n    }\n\n    void print() const {\n        std::cout << \"{\";\n        for(const auto& value: *this) {\n            std::cout << value << \", \";\n        }\n        std::cout << \"}\" << std::endl;\n    }\n};\n\n/*\nSetLazy<int> multiset_lazy // Uses multiset by default\nSetLazy<int, std::set> set_lazy; // Uses set explicitly\n*/\n"
  },
  {
    "path": "data_structures/sparse_table.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, T (*merge)(T, T)>\nclass SparseTable {\n  private:\n    int n;\n    vector<vector<T>> dp;\n    vector<int> prec_lg2;\n\n  public:\n    SparseTable() {\n        n = 0;\n        dp.clear();\n        prec_lg2.clear();\n    }\n\n    void init(const vector<T>& a) {\n        n = a.size();\n        prec_lg2.resize(n + 1);\n        for(int i = 2; i <= n; i++) {\n            prec_lg2[i] = prec_lg2[i >> 1] + 1;\n        }\n\n        dp.assign(prec_lg2[n] + 1, vector<T>(n));\n        dp[0] = a;\n\n        for(int j = 1; (1 << j) <= n; j++) {\n            for(int i = 0; i + (1 << j) <= n; i++) {\n                dp[j][i] = merge(dp[j - 1][i], dp[j - 1][i + (1 << (j - 1))]);\n            }\n        }\n    }\n\n    T query(int l, int r) {\n        int k = prec_lg2[r - l + 1];\n        return merge(dp[k][l], dp[k][r - (1 << k) + 1]);\n    }\n};\n\n// int min_custom(int a, int b) { return min(a, b); }\n// SparseTable<int, min_custom> tbl;\n"
  },
  {
    "path": "data_structures/sparse_table_disjoint.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, T (*merge)(T, T)>\nclass SparseTableDisjoint {\n  private:\n    int n;\n    vector<int> prec_lg2, mask;\n    vector<vector<T>> dp;\n    vector<T> a;\n\n    void init_dnc(int l, int r, int lvl) {\n        if(l == r) {\n            dp[lvl][l] = a[l];\n            return;\n        }\n\n        int m = (l + r) >> 1;\n        init_dnc(l, m, lvl + 1);\n        init_dnc(m + 1, r, lvl + 1);\n\n        dp[lvl][m] = a[m];\n        for(int i = m - 1; i >= l; i--) {\n            dp[lvl][i] = merge(a[i], dp[lvl][i + 1]);\n        }\n\n        dp[lvl][m + 1] = a[m + 1];\n        mask[m + 1] |= 1 << lvl;\n        for(int i = m + 2; i <= r; i++) {\n            dp[lvl][i] = merge(dp[lvl][i - 1], a[i]);\n            mask[i] |= 1 << lvl;\n        }\n    }\n\n  public:\n    SparseTableDisjoint() {\n        n = 0;\n        a.clear();\n        dp.clear();\n        prec_lg2.clear();\n        mask.clear();\n    }\n\n    void init(const vector<T>& _a) {\n        a = _a;\n        n = a.size();\n        prec_lg2.assign(4 * n + 1, 0);\n        for(int i = 2; i <= 4 * n; i++) {\n            prec_lg2[i] = prec_lg2[i >> 1] + 1;\n        }\n\n        dp.assign(prec_lg2[n] + 2, vector<T>(n));\n        mask.assign(n, 0);\n        init_dnc(0, n - 1, 0);\n    }\n\n    T query(int l, int r) {\n        if(l == r) {\n            return a[l];\n        }\n\n        int mask_diff = mask[l] ^ mask[r];\n        int k = prec_lg2[mask_diff & -mask_diff];\n        return merge(dp[k][l], dp[k][r]);\n    }\n};\n\n// int min_custom(int a, int b) { return min(a, b); }\n// sparse_table_disjoint<int, min_custom> st;\n"
  },
  {
    "path": "data_structures/treap.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class KeyT, class T, T (*merge_func)(T, T), uint64_t (*rng)()>\nstruct TreapNode {\n    KeyT key;\n    T data, subtree;\n    uint64_t prior;\n    size_t size;\n    TreapNode *left, *right;\n\n    TreapNode(KeyT key, T data)\n        : key(key), data(data), left(nullptr), right(nullptr), size(1) {\n        prior = rng();\n    }\n\n    void pull() {\n        subtree = data;\n        size = 1;\n        if(left) {\n            subtree = merge_func(left->subtree, subtree);\n            size += left->size;\n        }\n        if(right) {\n            subtree = merge_func(subtree, right->subtree);\n            size += right->size;\n        }\n    }\n\n    friend pair<TreapNode*, TreapNode*> split(TreapNode* t, KeyT key) {\n        if(!t) {\n            return {nullptr, nullptr};\n        }\n        if(key < t->key) {\n            auto [left, t_left] = split(t->left, key);\n            t->left = t_left;\n            t->pull();\n            return {left, t};\n        } else {\n            auto [t_right, right] = split(t->right, key);\n            t->right = t_right;\n            t->pull();\n            return {t, right};\n        }\n    }\n\n    friend pair<TreapNode*, TreapNode*> split_by_size(\n        TreapNode* t, size_t size\n    ) {\n        if(!t) {\n            return {nullptr, nullptr};\n        }\n\n        size_t left_size = t->left ? t->left->size : 0;\n        if(left_size >= size) {\n            auto [left, t_left] = split_by_size(t->left, size);\n            t->left = t_left;\n            t->pull();\n            return {left, t};\n        } else {\n            auto [t_right, right] =\n                split_by_size(t->right, size - 1 - left_size);\n            t->right = t_right;\n            t->pull();\n            return {t, right};\n        }\n    }\n\n    friend TreapNode* merge(TreapNode* l, TreapNode* r) {\n        if(!l || !r) {\n            return l ? l : r;\n        } else if(l->prior > r->prior) {\n            l->right = merge(l->right, r);\n            l->pull();\n            return l;\n        } else {\n            r->left = merge(l, r->left);\n            r->pull();\n            return r;\n        }\n    }\n\n    friend TreapNode* unordered_merge(TreapNode* l, TreapNode* r) {\n        if(!l) {\n            return r;\n        }\n        if(!r) {\n            return l;\n        }\n        if(l->prior < r->prior) {\n            swap(l, r);\n        }\n        auto [t1, t2] = split(r, l->key);\n        l->left = unordered_merge(l->left, t1);\n        l->right = unordered_merge(l->right, t2);\n        l->pull();\n        return l;\n    }\n\n    friend void insert_in(TreapNode*& t, TreapNode* it) {\n        if(!t) {\n            t = it;\n        } else if(it->prior > t->prior) {\n            auto [t1, t2] = split(t, it->key);\n            it->left = t1;\n            it->right = t2;\n            t = it;\n        } else {\n            insert_in(it->key < t->key ? t->left : t->right, it);\n        }\n        t->pull();\n    }\n\n    friend TreapNode* erase_from(\n        TreapNode*& t, KeyT key, bool delete_node = false\n    ) {\n        T return_data;\n        if(t->key == key) {\n            auto tmp = t;\n            t = merge(t->left, t->right);\n\n            return_data = tmp->data;\n            if(delete_node) {\n                delete tmp;\n                return_data = nullptr;\n            }\n        } else {\n            return_data =\n                erase_from(key < t->key ? t->left : t->right, key, delete_node);\n        }\n        if(t) {\n            t->pull();\n        }\n        return return_data;\n    }\n};\n\ntemplate<class KeyT, class T, T (*merge_func)(T, T)>\nclass Treap {\n  public:\n    static uint64_t rng() {\n        static mt19937_64 static_rng(random_device{}());\n        return static_rng();\n    }\n\n    using Node = TreapNode<KeyT, T, merge_func, Treap::rng>;\n\n    void _pull_all(Node* t) {\n        if(t) {\n            _pull_all(t->left);\n            _pull_all(t->right);\n            t->pull();\n        }\n    }\n\n    Node* root;\n\n    Treap() { root = nullptr; }\n    Treap(const vector<pair<KeyT, T>>& a) { build_cartesian_tree(a); }\n\n    void build_cartesian_tree(const vector<pair<KeyT, T>>& a) {\n        vector<Node*> st;\n\n        function<Node*(Node*)> recycle_stack = [&](Node* last) {\n            Node* new_last = st.back();\n            st.pop_back();\n            new_last->right = last;\n            return new_last;\n        };\n\n        for(const auto& [key, val]: a) {\n            Node* new_node = new Node(key, val);\n            Node* last = nullptr;\n            while(!st.empty() && st.back()->prior < new_node->prior) {\n                last = recycle_stack(last);\n            }\n\n            new_node->left = last;\n            st.push_back(new_node);\n        }\n\n        root = nullptr;\n        while(!st.empty()) {\n            root = recycle_stack(root);\n        }\n\n        _pull_all(root);\n    }\n\n    void insert(KeyT key, T data) {\n        Node* new_node = new Node(key, data);\n        insert_in(root, new_node);\n    }\n\n    Node* erase(KeyT key) { return erase_from(root, key); }\n\n    friend Treap<KeyT, T, merge_func> merge_treaps(\n        Treap<KeyT, T, merge_func> l, Treap<KeyT, T, merge_func> r\n    ) {\n        Treap<KeyT, T, merge_func> res;\n        res.root = unordered_merge(l.root, r.root);\n        return res;\n    }\n\n    int count_leq(KeyT max_key) {\n        int cnt = 0;\n        Node* cur = root;\n        while(cur) {\n            if(cur->key <= max_key) {\n                cnt += (cur->left ? cur->left->size : 0) + 1;\n                cur = cur->right;\n            } else {\n                cur = cur->left;\n            }\n        }\n        return cnt;\n    }\n};\n\n// pair<int64_t, int64_t> plus_func(\n//     pair<int64_t, int64_t> a, pair<int64_t, int64_t> b\n// ) {\n//     return {a.first + b.first, a.second + b.second};\n// }\n\n// using TreapWithCount = Treap<int64_t, pair<int64_t, int64_t>, plus_func>;\n// using Node = TreapWithCount::Node;\n\n// pair<Node*, Node*> split_by_count(Node* t, int64_t k) {\n//     if(!t) {\n//         return {nullptr, nullptr};\n//     }\n//     if(t->left && t->left->subtree.first >= k) {\n//         auto [left, t_left] = split_by_count(t->left, k);\n//         t->left = t_left;\n//         t->pull();\n//         return {left, t};\n//     } else {\n//         k -= (t->left ? t->left->subtree.first : 0);\n//         if(k < t->data.first) {\n//             Node* new_left = new Node(t->key, {k, k * t->key});\n//             t->data.first -= k;\n//             t->data.second = t->data.first * t->key;\n\n//             insert_in(t->left, new_left);\n//             new_left = t->left;\n//             t->left = nullptr;\n//             t->pull();\n//             return {new_left, t};\n//         }\n\n//         auto [t_right, new_right] = split_by_count(t->right, k -\n//         t->data.first); t->right = t_right; t->pull(); return {t, new_right};\n//     }\n// }\n"
  },
  {
    "path": "data_structures/treap_lazy.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<\n    class KeyT, class T, T (*merge_func)(T, T), class LazyT, uint64_t (*rng)()>\nstruct TreapNode {\n    KeyT key;\n    T data, subtree;\n    uint64_t prior;\n    size_t size;\n    TreapNode *left, *right;\n    LazyT lazy;\n\n    TreapNode(KeyT key, T data)\n        : key(key), data(data), left(nullptr), right(nullptr), size(1) {\n        prior = rng();\n        lazy = LazyT();\n    }\n\n    void pull() {\n        subtree = data;\n        size = 1;\n        if(left) {\n            left->push();\n            subtree = merge_func(left->subtree, subtree);\n            size += left->size;\n        }\n        if(right) {\n            right->push();\n            subtree = merge_func(subtree, right->subtree);\n            size += right->size;\n        }\n    }\n\n    void push() { lazy.apply_lazy(this); }\n\n    friend void push_lazy(TreapNode* t) {\n        if(t) {\n            t->push();\n        }\n    }\n\n    friend pair<TreapNode*, TreapNode*> split(TreapNode* t, KeyT key) {\n        if(!t) {\n            return {nullptr, nullptr};\n        }\n\n        t->push();\n        if(key < t->key) {\n            auto [left, t_left] = split(t->left, key);\n            t->left = t_left;\n            t->pull();\n            return {left, t};\n        } else {\n            auto [t_right, right] = split(t->right, key);\n            t->right = t_right;\n            t->pull();\n            return {t, right};\n        }\n    }\n\n    friend pair<TreapNode*, TreapNode*> split_by_size(\n        TreapNode* t, size_t size\n    ) {\n        if(!t) {\n            return {nullptr, nullptr};\n        }\n\n        t->push();\n        size_t left_size = t->left ? t->left->size : 0;\n        if(left_size >= size) {\n            auto [left, t_left] = split_by_size(t->left, size);\n            t->left = t_left;\n            t->pull();\n            return {left, t};\n        } else {\n            auto [t_right, right] =\n                split_by_size(t->right, size - 1 - left_size);\n            t->right = t_right;\n            t->pull();\n            return {t, right};\n        }\n    }\n\n    friend TreapNode* merge(TreapNode* l, TreapNode* r) {\n        push_lazy(l);\n        push_lazy(r);\n        if(!l || !r) {\n            return l ? l : r;\n        } else if(l->prior > r->prior) {\n            l->right = merge(l->right, r);\n            l->pull();\n            return l;\n        } else {\n            r->left = merge(l, r->left);\n            r->pull();\n            return r;\n        }\n    }\n\n    friend TreapNode* unordered_merge(TreapNode* l, TreapNode* r) {\n        push_lazy(l);\n        push_lazy(r);\n        if(!l) {\n            return r;\n        }\n        if(!r) {\n            return l;\n        }\n        if(l->prior < r->prior) {\n            swap(l, r);\n        }\n        auto [t1, t2] = split(r, l->key);\n        l->left = unordered_merge(l->left, t1);\n        l->right = unordered_merge(l->right, t2);\n        l->pull();\n        return l;\n    }\n\n    friend void insert_in(TreapNode*& t, TreapNode* it) {\n        if(!t) {\n            t = it;\n        } else {\n            t->push();\n            if(it->prior > t->prior) {\n                auto [t1, t2] = split(t, it->key);\n                it->left = t1;\n                it->right = t2;\n                t = it;\n            } else {\n                insert_in(it->key < t->key ? t->left : t->right, it);\n            }\n        }\n        t->pull();\n    }\n\n    friend TreapNode* erase_from(\n        TreapNode*& t, KeyT key, bool delete_node = false\n    ) {\n        t->push();\n        T return_data;\n        if(t->key == key) {\n            auto tmp = t;\n            t = merge(t->left, t->right);\n\n            return_data = tmp->data;\n            if(delete_node) {\n                delete tmp;\n            }\n        } else {\n            return_data =\n                erase_from(key < t->key ? t->left : t->right, key, delete_node);\n        }\n        if(t) {\n            t->pull();\n        }\n        return return_data;\n    }\n};\n\ntemplate<class KeyT, class T, T (*merge_func)(T, T), class LazyT>\nclass Treap {\n  public:\n    static uint64_t rng() {\n        static mt19937_64 static_rng(random_device{}());\n        // FOR DEBUG:\n        // static mt19937_64 static_rng(42);\n        return static_rng();\n    }\n\n    using Node = TreapNode<KeyT, T, merge_func, LazyT, Treap::rng>;\n\n    void _pull_all(Node* t) {\n        if(t) {\n            t->push();\n            _pull_all(t->left);\n            _pull_all(t->right);\n            t->pull();\n        }\n    }\n\n    Node* root;\n\n    Treap() { root = nullptr; }\n    Treap(const vector<pair<KeyT, T>>& a) { build_cartesian_tree(a); }\n\n    void build_cartesian_tree(const vector<pair<KeyT, T>>& a) {\n        vector<Node*> st;\n\n        function<Node*(Node*)> recycle_stack = [&](Node* last) {\n            Node* new_last = st.back();\n            st.pop_back();\n            new_last->right = last;\n            return new_last;\n        };\n\n        for(const auto& [key, val]: a) {\n            Node* new_node = new Node(key, val);\n            Node* last = nullptr;\n            while(!st.empty() && st.back()->prior < new_node->prior) {\n                last = recycle_stack(last);\n            }\n\n            new_node->left = last;\n            st.push_back(new_node);\n        }\n\n        root = nullptr;\n        while(!st.empty()) {\n            root = recycle_stack(root);\n        }\n\n        _pull_all(root);\n    }\n\n    void insert(KeyT key, T data) {\n        Node* new_node = new Node(key, data);\n        insert_in(root, new_node);\n    }\n\n    void erase(KeyT key) { return erase_from(root, key); }\n\n    friend Treap<KeyT, T, merge_func, LazyT> merge_treaps(\n        Treap<KeyT, T, merge_func, LazyT> l, Treap<KeyT, T, merge_func, LazyT> r\n    ) {\n        Treap<KeyT, T, merge_func, LazyT> res;\n        res.root = unordered_merge(l.root, r.root);\n        return res;\n    }\n};\n\n// template<class T>\n// struct ReverseLazy {\n//     bool should_reverse;\n\n//     ReverseLazy() { should_reverse = false; }\n\n//     template<class G, uint64_t (*rng)(), T (*merge_func)(T, T)>\n//     void apply_lazy(TreapNode<G, T, merge_func, ReverseLazy, rng>* node) {\n//         if(!node || !should_reverse) {\n//             return;\n//         }\n\n//         swap(node->left, node->right);\n//         if(node->left) {\n//             node->left->lazy.should_reverse ^= true;\n//         }\n//         if(node->right) {\n//             node->right->lazy.should_reverse ^= true;\n//         }\n\n//         should_reverse = false;\n//     }\n// };\n\n// struct EmptyMonoid {\n//     static EmptyMonoid merge(EmptyMonoid a, EmptyMonoid b) {\n//         return EmptyMonoid();\n//     }\n// };\n\n// template<class T>\n// struct AddLazy {\n//     T add_key = 0;\n//     T add_data = 0;\n\n//     template<class G, uint64_t (*rng)(), T (*merge_func)(T, T)>\n//     void apply_lazy(TreapNode<pair<T, G>, T, merge_func, AddLazy, rng>* node)\n//     {\n//         if(!node || (add_key == 0 && add_data == 0)) {\n//             return;\n//         }\n\n//         node->key.first += add_key;\n//         node->data += add_data;\n//         node->subtree += add_data * (T)node->size;\n\n//         if(node->left) {\n//             node->left->lazy.add_data += add_data;\n//             node->left->lazy.add_key += add_key;\n//         }\n\n//         if(node->right) {\n//             node->right->lazy.add_data += add_data;\n//             node->right->lazy.add_key += add_key;\n//         }\n\n//         add_key = 0;\n//         add_data = 0;\n//     }\n// };\n\n// int64_t add(int64_t a, int64_t b) { return a + b; }\n// using TreapWithLazy = Treap<pair<int64_t, int>, int64_t, add,\n// AddLazy<int64_t>>; using Node = TreapWithLazy::Node;\n\n// Tested on https://codeforces.com/contest/702/problem/F.\n// https://codeforces.com/contest/702/submission/283296920\n// https://codeforces.com/problemsets/acmsguru/submission/99999/294488144\n"
  },
  {
    "path": "data_structures/wavelet_tree.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// wvlt = new WaveletTree();\n// wvlt->init(arr, 0, n);                     \n// \n// All queries are 1-indexed.\n\nclass WaveletTree {\n  private:\n    int lo{1}, hi{0};\n    WaveletTree *left{nullptr}, *right{nullptr};\n    vector<int> b;\n    int psz{0};\n\n  public:\n    WaveletTree() = default;\n\n    void init(const vector<int>& arr, int x, int y) {\n        lo = x;\n        hi = y;\n        if(lo == hi || arr.empty()) {\n            return;\n        }\n        int mid = (lo + hi) >> 1;\n        auto f = [mid](int x) { return x <= mid; };\n        b.resize(arr.size() + 1);\n        b[0] = 0;\n        for(size_t i = 0; i < arr.size(); ++i) {\n            b[i + 1] = b[i] + f(arr[i]);\n        }\n        psz = arr.size();\n\n        // Create a mutable copy of the array\n        vector<int> arr_copy(arr);\n        auto pivot = stable_partition(arr_copy.begin(), arr_copy.end(), f);\n\n        left = new WaveletTree();\n        right = new WaveletTree();\n        left->init(vector<int>(arr_copy.begin(), pivot), lo, mid);\n        right->init(vector<int>(pivot, arr_copy.end()), mid + 1, hi);\n    }\n\n    int kth(int l, int r, int k) const {\n        if(l > r) {\n            return 0;\n        }\n        if(lo == hi) {\n            return lo;\n        }\n        int inLeft = b[r] - b[l - 1], lb = b[l - 1], rb = b[r];\n        if(k <= inLeft) {\n            return left->kth(lb + 1, rb, k);\n        }\n        return right->kth(l - lb, r - rb, k - inLeft);\n    }\n\n    int LTE(int l, int r, int k) const {\n        if(l > r || k < lo) {\n            return 0;\n        }\n        if(hi <= k) {\n            return r - l + 1;\n        }\n        int lb = b[l - 1], rb = b[r];\n        return left->LTE(lb + 1, rb, k) + right->LTE(l - lb, r - rb, k);\n    }\n\n    int count(int l, int r, int k) const {\n        if(l > r || k < lo || k > hi) {\n            return 0;\n        }\n        if(lo == hi) {\n            return r - l + 1;\n        }\n        int lb = b[l - 1], rb = b[r];\n        int mid = (lo + hi) >> 1;\n        if(k <= mid) {\n            return left->count(lb + 1, rb, k);\n        }\n        return right->count(l - lb, r - rb, k);\n    }\n};\n"
  },
  {
    "path": "dp_optimizations/convex_hull_trick.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, bool maximum = true>\nclass ConvexHullTrick {\n  public:\n    static constexpr T inf = is_integral_v<T> ? numeric_limits<T>::max()\n                                              : numeric_limits<T>::infinity();\n\n    T div(T a, T b) {\n        if constexpr(is_integral_v<T>) {\n            return a / b - ((a ^ b) < 0 && a % b);\n        } else {\n            return a / b;\n        }\n    }\n\n    struct Line {\n        mutable T k, m, p;\n        bool operator<(const Line& o) const { return k < o.k; }\n        bool operator<(T x) const { return p < x; }\n    };\n\n    multiset<Line, less<>> hull;\n\n    using Iter = typename multiset<Line, less<>>::iterator;\n\n    bool intersect(Iter x, Iter y) {\n        if(y == hull.end()) {\n            return x->p = inf, 0;\n        }\n        if(x->k == y->k) {\n            x->p = x->m > y->m ? inf : -inf;\n        } else {\n            x->p = div(y->m - x->m, x->k - y->k);\n        }\n        return x->p >= y->p;\n    }\n\n    void add(T k, T m) {\n        if constexpr(!maximum) {\n            k = -k;\n            m = -m;\n        }\n        auto z = hull.insert({k, m, 0}), y = z++, x = y;\n        while(intersect(y, z)) {\n            z = hull.erase(z);\n        }\n        if(x != hull.begin() && intersect(--x, y)) {\n            intersect(x, y = hull.erase(y));\n        }\n        while((y = x) != hull.begin() && (--x)->p >= y->p) {\n            intersect(x, hull.erase(y));\n        }\n    }\n\n    T query(T x) {\n        assert(!hull.empty());\n        auto l = *hull.lower_bound(x);\n        T res = l.k * x + l.m;\n        if constexpr(!maximum) {\n            res = -res;\n        }\n        return res;\n    }\n};\n"
  },
  {
    "path": "geometry/dynamic_convex_hull.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/geometry/point.hpp>\nusing namespace std;\n\n// Tested on problem 277 from SGU:\n// https://codeforces.com/problemsets/acmsguru/problem/99999/277\n\nclass DynamicConvexHull {\n  public:\n    set<Point> lower;\n    set<Point> upper;\n\n  private:\n    coord_t lower_sum = 0;\n    coord_t upper_sum = 0;\n\n    using Iter = set<Point>::iterator;\n\n    void add_to_hull(set<Point>& hull, coord_t& sum, const Point& p, int sign) {\n        if(hull.empty()) {\n            hull.insert(p);\n            return;\n        }\n\n        auto right = hull.lower_bound(p);\n\n        if(right != hull.end() && right->x == p.x) {\n            if(sign * (p.y - right->y) >= 0) {\n                return;\n            }\n            Iter left = (right != hull.begin()) ? prev(right) : hull.end();\n            Iter right_next = next(right);\n            if(left != hull.end()) {\n                sum -= (*left) ^ (*right);\n            }\n            if(right_next != hull.end()) {\n                sum -= (*right) ^ (*right_next);\n            }\n            if(left != hull.end() && right_next != hull.end()) {\n                sum += (*left) ^ (*right_next);\n            }\n            hull.erase(right);\n            right = right_next;\n        }\n\n        Iter left = (right != hull.begin()) ? prev(right) : hull.end();\n\n        if(left != hull.end() && right != hull.end()) {\n            if(sign * ccw(*left, *right, p) >= 0) {\n                return;\n            }\n            sum -= (*left) ^ (*right);\n        }\n\n        while(left != hull.end() && left != hull.begin()) {\n            Iter left_left = prev(left);\n            if(sign * ccw(*left_left, *left, p) > 0) {\n                break;\n            }\n            sum -= (*left_left) ^ (*left);\n            hull.erase(left);\n            left = left_left;\n        }\n\n        while(right != hull.end()) {\n            Iter right_next = next(right);\n            if(right_next == hull.end()) {\n                break;\n            }\n            if(sign * ccw(p, *right, *right_next) > 0) {\n                break;\n            }\n            sum -= (*right) ^ (*right_next);\n            hull.erase(right);\n            right = right_next;\n        }\n\n        if(left != hull.end()) {\n            sum += (*left) ^ p;\n        }\n        if(right != hull.end()) {\n            sum += p ^ (*right);\n        }\n\n        hull.insert(p);\n    }\n\n  public:\n    DynamicConvexHull() = default;\n\n    void add(const Point& p) {\n        add_to_hull(lower, lower_sum, p, 1);\n        add_to_hull(upper, upper_sum, p, -1);\n    }\n\n    coord_t doubled_area() const {\n        if(lower.empty() || upper.empty()) {\n            return 0;\n        }\n\n        coord_t result = lower_sum - upper_sum;\n\n        const Point& right_lower = *lower.rbegin();\n        const Point& right_upper = *upper.rbegin();\n        if(!(right_lower == right_upper)) {\n            result += right_lower ^ right_upper;\n        }\n\n        const Point& left_lower = *lower.begin();\n        const Point& left_upper = *upper.begin();\n        if(!(left_lower == left_upper)) {\n            result += left_upper ^ left_lower;\n        }\n\n        return result;\n    }\n};\n"
  },
  {
    "path": "geometry/halfplane_intersection.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/geometry/point.hpp>\n\nusing namespace std;\n\nusing Line = pair<Point, Point>;\n\nclass HalfPlaneIntersection {\n  private:\n    vector<Line> lines;\n    deque<int> dq;\n    bool empty_intersection = false;\n\n    Point dir(int i) const { return lines[i].second - lines[i].first; }\n\n    bool outside(int i, const Point& pt) const {\n        return ccw(lines[i].first, lines[i].second, pt) < 0;\n    }\n\n    Point inter(int i, int j) const {\n        return line_line_intersection(\n            lines[i].first, lines[i].second, lines[j].first, lines[j].second\n        );\n    }\n\n    bool is_parallel(int i, int j) const {\n        return abs(dir(i) ^ dir(j)) < Point::eps;\n    }\n\n    bool same_direction(int i, int j) const { return (dir(i) * dir(j)) > 0; }\n\n  public:\n    static vector<Line> sort_by_angle(const vector<Line>& lines) {\n        vector<Line> sorted = lines;\n        sort(sorted.begin(), sorted.end(), [](const Line& a, const Line& b) {\n            return (a.second - a.first).angle() < (b.second - b.first).angle();\n        });\n        return sorted;\n    }\n\n    HalfPlaneIntersection(const vector<Line>& lines, bool is_sorted = false)\n        : lines(is_sorted ? lines : sort_by_angle(lines)) {\n        int n = this->lines.size();\n\n        for(int i = 0; i < n; i++) {\n            while(dq.size() > 1 &&\n                  outside(i, inter(dq.back(), dq[dq.size() - 2]))) {\n                dq.pop_back();\n            }\n            while(dq.size() > 1 && outside(i, inter(dq.front(), dq[1]))) {\n                dq.pop_front();\n            }\n\n            if(!dq.empty() && is_parallel(i, dq.back())) {\n                if(!same_direction(i, dq.back())) {\n                    empty_intersection = true;\n                    return;\n                }\n                if(outside(i, this->lines[dq.back()].first)) {\n                    dq.pop_back();\n                } else {\n                    continue;\n                }\n            }\n\n            dq.push_back(i);\n        }\n\n        while(dq.size() > 2 &&\n              outside(dq.front(), inter(dq.back(), dq[dq.size() - 2]))) {\n            dq.pop_back();\n        }\n        while(dq.size() > 2 && outside(dq.back(), inter(dq.front(), dq[1]))) {\n            dq.pop_front();\n        }\n\n        if(dq.size() < 3) {\n            empty_intersection = true;\n        }\n    }\n\n    bool is_non_empty() const { return !empty_intersection; }\n\n    vector<Point> get_polygon() const {\n        if(empty_intersection) {\n            return {};\n        }\n        vector<Point> result(dq.size());\n        for(size_t i = 0; i + 1 < dq.size(); i++) {\n            result[i] = inter(dq[i], dq[i + 1]);\n        }\n        result.back() = inter(dq.back(), dq.front());\n        return result;\n    }\n};\n"
  },
  {
    "path": "geometry/point.hpp",
    "content": "#ifndef POINT_HPP\n#define POINT_HPP\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing coord_t = double;\n\nstruct Point {\n    static constexpr coord_t eps = 1e-9;\n    static inline const coord_t PI = acos((coord_t)-1.0);\n\n    coord_t x, y;\n    Point(coord_t x = 0, coord_t y = 0) : x(x), y(y) {}\n\n    Point operator+(const Point& p) const { return Point(x + p.x, y + p.y); }\n    Point operator-(const Point& p) const { return Point(x - p.x, y - p.y); }\n    Point operator*(coord_t c) const { return Point(x * c, y * c); }\n    Point operator/(coord_t c) const { return Point(x / c, y / c); }\n\n    coord_t operator*(const Point& p) const { return x * p.x + y * p.y; }\n    coord_t operator^(const Point& p) const { return x * p.y - y * p.x; }\n\n    bool operator==(const Point& p) const { return x == p.x && y == p.y; }\n    bool operator!=(const Point& p) const { return x != p.x || y != p.y; }\n    bool operator<(const Point& p) const {\n        return x != p.x ? x < p.x : y < p.y;\n    }\n    bool operator>(const Point& p) const {\n        return x != p.x ? x > p.x : y > p.y;\n    }\n    bool operator<=(const Point& p) const {\n        return x != p.x ? x < p.x : y <= p.y;\n    }\n    bool operator>=(const Point& p) const {\n        return x != p.x ? x > p.x : y >= p.y;\n    }\n\n    coord_t norm2() const { return x * x + y * y; }\n    coord_t norm() const { return sqrt(norm2()); }\n    coord_t angle() const { return atan2(y, x); }\n\n    Point rotate(coord_t a) const {\n        return Point(x * cos(a) - y * sin(a), x * sin(a) + y * cos(a));\n    }\n\n    Point perp() const { return Point(-y, x); }\n    Point unit() const { return *this / norm(); }\n    Point normal() const { return perp().unit(); }\n    Point project(const Point& p) const {\n        return *this * (*this * p) / norm2();\n    }\n    Point reflect(const Point& p) const {\n        return *this * 2 * (*this * p) / norm2() - p;\n    }\n\n    friend ostream& operator<<(ostream& os, const Point& p) {\n        return os << p.x << ' ' << p.y;\n    }\n    friend istream& operator>>(istream& is, Point& p) {\n        return is >> p.x >> p.y;\n    }\n\n    friend int ccw(const Point& a, const Point& b, const Point& c) {\n        coord_t v = (b - a) ^ (c - a);\n        if(-eps <= v && v <= eps) {\n            return 0;\n        } else if(v > 0) {\n            return 1;\n        } else {\n            return -1;\n        }\n    }\n\n    friend bool point_on_segment(\n        const Point& a, const Point& b, const Point& p\n    ) {\n        return ccw(a, b, p) == 0 && p.x >= min(a.x, b.x) - eps &&\n               p.x <= max(a.x, b.x) + eps && p.y >= min(a.y, b.y) - eps &&\n               p.y <= max(a.y, b.y) + eps;\n    }\n\n    friend bool point_in_triangle(\n        const Point& a, const Point& b, const Point& c, const Point& p\n    ) {\n        int d1 = ccw(a, b, p);\n        int d2 = ccw(b, c, p);\n        int d3 = ccw(c, a, p);\n        return (d1 >= 0 && d2 >= 0 && d3 >= 0) ||\n               (d1 <= 0 && d2 <= 0 && d3 <= 0);\n    }\n\n    friend Point line_line_intersection(\n        const Point& a1, const Point& b1, const Point& a2, const Point& b2\n    ) {\n        return a1 +\n               (b1 - a1) * ((a2 - a1) ^ (b2 - a2)) / ((b1 - a1) ^ (b2 - a2));\n    }\n\n    friend bool collinear(const Point& a, const Point& b) {\n        return abs(a ^ b) < eps;\n    }\n\n    friend Point circumcenter(const Point& a, const Point& b, const Point& c) {\n        Point mid_ab = (a + b) / 2.0;\n        Point mid_ac = (a + c) / 2.0;\n        Point perp_ab = (b - a).perp();\n        Point perp_ac = (c - a).perp();\n        return line_line_intersection(\n            mid_ab, mid_ab + perp_ab, mid_ac, mid_ac + perp_ac\n        );\n    }\n\n    friend coord_t arc_area(\n        const Point& center, coord_t r, const Point& p1, const Point& p2\n    ) {\n        coord_t theta1 = (p1 - center).angle();\n        coord_t theta2 = (p2 - center).angle();\n        if(theta2 < theta1 - eps) {\n            theta2 += 2 * PI;\n        }\n\n        coord_t d_theta = theta2 - theta1;\n        coord_t cx = center.x, cy = center.y;\n        coord_t area = r * cx * (sin(theta2) - sin(theta1)) -\n                       r * cy * (cos(theta2) - cos(theta1)) + r * r * d_theta;\n        return area / 2.0;\n    }\n\n    friend vector<Point> intersect_circles(\n        const Point& c1, coord_t r1, const Point& c2, coord_t r2\n    ) {\n        Point d = c2 - c1;\n        coord_t dist = d.norm();\n\n        if(dist > r1 + r2 + eps || dist < abs(r1 - r2) - eps || dist < eps) {\n            return {};\n        }\n\n        coord_t a = (r1 * r1 - r2 * r2 + dist * dist) / (2 * dist);\n        coord_t h_sq = r1 * r1 - a * a;\n        if(h_sq < -eps) {\n            return {};\n        }\n        if(h_sq < 0) {\n            h_sq = 0;\n        }\n        coord_t h = sqrt(h_sq);\n\n        Point mid = c1 + d.unit() * a;\n        Point perp_dir = d.perp().unit();\n\n        if(h < eps) {\n            return {mid};\n        }\n        return {mid + perp_dir * h, mid - perp_dir * h};\n    }\n\n    friend optional<Point> intersect_ray_segment(\n        const Point& ray_start, const Point& ray_through, const Point& seg_a,\n        const Point& seg_b\n    ) {\n        Point ray_dir = ray_through - ray_start;\n        if(ray_dir.norm2() < Point::eps) {\n            return {};\n        }\n        Point seg_dir = seg_b - seg_a;\n        coord_t denom = ray_dir ^ seg_dir;\n        if(fabs(denom) < eps) {\n            return {};\n        }\n        coord_t t = ((seg_a - ray_start) ^ seg_dir) / denom;\n        if(t < eps) {\n            return {};\n        }\n        coord_t s = ((seg_a - ray_start) ^ ray_dir) / denom;\n        if(s < eps || s > 1 - eps) {\n            return {};\n        }\n        return ray_start + ray_dir * t;\n    }\n};\n\n#endif  // POINT_HPP\n"
  },
  {
    "path": "geometry/polygon.hpp",
    "content": "#ifndef POLYGON_HPP\n#define POLYGON_HPP\n\n#include <bits/stdc++.h>\n#include <coding_library/geometry/point.hpp>\nusing namespace std;\n\nclass Polygon {\n  public:\n    vector<Point> points;\n\n    Polygon() {}\n    Polygon(const vector<Point>& points) : points(points) {}\n\n    int size() const { return points.size(); }\n    const Point& operator[](int i) const { return points[i]; }\n    Point& operator[](int i) { return points[i]; }\n\n    coord_t area() const {\n        coord_t a = 0;\n        for(int i = 0; i < size(); i++) {\n            a += points[i] ^ points[(i + 1) % size()];\n        }\n        return a / 2.0;\n    }\n};\n\nclass PointInConvexPolygon {\n  private:\n    Point min_point;\n    vector<Point> points_by_angle;\n\n    void prepare() {\n        points_by_angle = polygon.points;\n        vector<Point>::iterator min_point_it =\n            min_element(points_by_angle.begin(), points_by_angle.end());\n        min_point = *min_point_it;\n\n        points_by_angle.erase(min_point_it);\n        sort(\n            points_by_angle.begin(), points_by_angle.end(),\n            [&](const Point& a, const Point& b) {\n                int d = ccw(min_point, a, b);\n                if(d != 0) {\n                    return d > 0;\n                }\n                return (a - min_point).norm2() < (b - min_point).norm2();\n            }\n        );\n    }\n\n  public:\n    Polygon polygon;\n    PointInConvexPolygon(const Polygon& polygon) : polygon(polygon) {\n        prepare();\n    }\n\n    bool contains(const Point& p) const {\n        int l = 0, r = (int)points_by_angle.size() - 1;\n        while(r - l > 1) {\n            int m = (l + r) / 2;\n            if(ccw(min_point, points_by_angle[m], p) >= 0) {\n                l = m;\n            } else {\n                r = m;\n            }\n        }\n\n        return point_in_triangle(\n            min_point, points_by_angle[l], points_by_angle[r], p\n        );\n    }\n};\n\nclass ConvexHull : public Polygon {\n  public:\n    int lower_end;\n    vector<Point> lower, upper;\n\n    ConvexHull(const vector<Point>& points) {\n        this->points = points;\n        sort(this->points.begin(), this->points.end());\n        this->points.erase(\n            unique(this->points.begin(), this->points.end()), this->points.end()\n        );\n\n        if(this->points.size() <= 2) {\n            lower_end = (int)this->points.size() - 1;\n            lower = this->points;\n            upper = {this->points.back()};\n            if(this->points.size() > 1) {\n                upper.push_back(this->points.front());\n            }\n            return;\n        }\n\n        vector<int> hull = {0};\n        vector<bool> used(this->points.size());\n\n        function<void(int, int)> expand_hull = [&](int i, int min_hull_size) {\n            while((int)hull.size() >= min_hull_size &&\n                  ccw(this->points[hull[hull.size() - 2]],\n                      this->points[hull.back()], this->points[i]) >= 0) {\n                used[hull.back()] = false;\n                hull.pop_back();\n            }\n            hull.push_back(i);\n            used[i] = true;\n        };\n\n        for(int i = 1; i < (int)this->points.size(); i++) {\n            expand_hull(i, 2);\n        }\n\n        int uhs = hull.size();\n        for(int i = (int)this->points.size() - 2; i >= 0; i--) {\n            if(!used[i]) {\n                expand_hull(i, uhs + 1);\n            }\n        }\n\n        hull.pop_back();\n\n        vector<Point> pts;\n        for(int i: hull) {\n            pts.push_back(this->points[i]);\n        }\n        reverse(pts.begin(), pts.end());\n        this->points = std::move(pts);\n\n        lower_end = size() - uhs;\n        lower.assign(\n            this->points.begin(), this->points.begin() + lower_end + 1\n        );\n        upper.assign(this->points.begin() + lower_end, this->points.end());\n        upper.push_back(this->points[0]);\n    }\n\n    pair<int, int> tangents_from(const Point& p) const {\n        int n = size();\n        if(n <= 1) {\n            return {0, 0};\n        }\n\n        int a = 0, b = 0;\n        auto update = [&](int id) {\n            id %= n;\n            if(ccw(p, points[a], points[id]) > 0) {\n                a = id;\n            }\n            if(ccw(p, points[b], points[id]) < 0) {\n                b = id;\n            }\n        };\n\n        auto bin_search = [&](int low, int high) {\n            if(low >= high) {\n                return;\n            }\n            update(low);\n            int sl = ccw(p, points[low % n], points[(low + 1) % n]);\n            while(low + 1 < high) {\n                int mid = (low + high) / 2;\n                if(ccw(p, points[mid % n], points[(mid + 1) % n]) == sl) {\n                    low = mid;\n                } else {\n                    high = mid;\n                }\n            }\n            update(high);\n        };\n\n        int lid =\n            (int)(lower_bound(lower.begin(), lower.end(), p) - lower.begin());\n        bin_search(0, lid);\n        bin_search(lid, (int)lower.size() - 1);\n\n        int uid =\n            (int)(lower_bound(upper.begin(), upper.end(), p, greater<Point>()) -\n                  upper.begin());\n        int base = lower_end;\n        bin_search(base, base + uid);\n        bin_search(base + uid, base + (int)upper.size() - 1);\n        return {a, b};\n    }\n};\n\n#endif  // POLYGON_HPP\n"
  },
  {
    "path": "geometry/voronoi.hpp",
    "content": "#ifndef VORONOI_HPP\n#define VORONOI_HPP\n\n#include <bits/stdc++.h>\n#include <coding_library/geometry/point.hpp>\nusing namespace std;\n\n// Variation of code by Monogon: https://codeforces.com/blog/entry/85638.\n// We rotate the points with a small angle as the implementation doesn't\n// directly handle the case of two equal X coordinates.\n\nclass VoronoiDiagram {\n  private:\n    static constexpr coord_t INF = 1e100;\n    static inline coord_t sweep_x;\n\n    struct Arc {\n        mutable Point p, q;\n        mutable int id = 0, i;\n\n        Arc(const Point& p, const Point& q, int i) : p(p), q(q), i(i) {}\n\n        coord_t get_y(coord_t x) const {\n            if(q.y == INF) {\n                return INF;\n            }\n            x += Point::eps;\n            Point mid = (p + q) / 2.0;\n            Point dir = (p - mid).perp();\n            coord_t D = (x - p.x) * (x - q.x);\n            if(D < 0) {\n                return -INF;\n            }\n\n            if(abs(dir.y) < Point::eps) {\n                return (x < mid.x) ? -INF : INF;\n            }\n\n            return mid.y +\n                   ((mid.x - x) * dir.x + sqrtl(D) * dir.norm()) / dir.y;\n        }\n\n        bool operator<(const coord_t& y) const { return get_y(sweep_x) < y; }\n\n        bool operator<(const Arc& o) const {\n            return get_y(sweep_x) < o.get_y(sweep_x);\n        }\n    };\n\n    using Beach = multiset<Arc, less<>>;\n\n    struct Event {\n        coord_t x;\n        int id;\n        Beach::iterator it;\n\n        Event(coord_t x, int id, Beach::iterator it) : x(x), id(id), it(it) {}\n\n        bool operator<(const Event& e) const { return x > e.x; }\n    };\n\n    Beach beach_line;\n    vector<pair<Point, int>> vertices;\n    priority_queue<Event> event_queue;\n    vector<pair<int, int>> edges;\n    vector<bool> valid;\n    int n, next_vertex_id;\n\n    void update_vertex_event(Beach::iterator it) {\n        if(it->i == -1) {\n            return;\n        }\n\n        valid[-it->id] = false;\n        auto prev_it = prev(it);\n\n        if(collinear(it->q - it->p, prev_it->p - it->p)) {\n            return;\n        }\n\n        it->id = --next_vertex_id;\n        valid.push_back(true);\n\n        Point center = circumcenter(it->p, it->q, prev_it->p);\n        coord_t event_x = center.x + (center - it->p).norm();\n\n        bool valid_event =\n            event_x > sweep_x - Point::eps &&\n            prev_it->get_y(event_x) + Point::eps > it->get_y(event_x);\n        if(valid_event) {\n            event_queue.push(Event(event_x, it->id, it));\n        }\n    }\n\n    void add_edge(int i, int j) {\n        if(i == -1 || j == -1) {\n            return;\n        }\n        edges.push_back({vertices[i].second, vertices[j].second});\n    }\n\n    void add_point(int i) {\n        Point p = vertices[i].first;\n\n        auto split_it = beach_line.lower_bound(p.y);\n        auto new_it = beach_line.insert(split_it, Arc(p, split_it->p, i));\n        auto prev_it =\n            beach_line.insert(new_it, Arc(split_it->p, p, split_it->i));\n\n        add_edge(i, split_it->i);\n\n        update_vertex_event(prev_it);\n        update_vertex_event(new_it);\n        update_vertex_event(split_it);\n    }\n\n    void remove_arc(Beach::iterator it) {\n        auto prev_it = prev(it);\n        auto next_it = next(it);\n\n        beach_line.erase(it);\n        prev_it->q = next_it->p;\n\n        add_edge(prev_it->i, next_it->i);\n\n        update_vertex_event(prev_it);\n        update_vertex_event(next_it);\n    }\n\n  public:\n    VoronoiDiagram(const vector<Point>& points, bool fix_coordinates = true) {\n        n = points.size();\n        vertices.resize(n);\n\n        for(int i = 0; i < n; i++) {\n            vertices[i] = {points[i], i};\n        }\n\n        if(fix_coordinates && n > 0) {\n            // Rotate around center by 1.0 radians.\n            for(int i = 0; i < n; i++) {\n                vertices[i].first = vertices[i].first.rotate(1.0);\n            }\n        }\n\n        sort(vertices.begin(), vertices.end());\n    }\n\n    vector<pair<int, int>> compute(coord_t X = 1e9) {\n        edges.clear();\n        beach_line.clear();\n        event_queue = priority_queue<Event>();\n\n        X *= 3;\n        beach_line.insert(Arc(Point(-X, -X), Point(-X, X), -1));\n        beach_line.insert(Arc(Point(-X, X), Point(INF, INF), -1));\n\n        for(int i = 0; i < n; i++) {\n            event_queue.push(Event(vertices[i].first.x, i, beach_line.end()));\n        }\n\n        next_vertex_id = 0;\n        valid.assign(1, false);\n\n        while(!event_queue.empty()) {\n            Event e = event_queue.top();\n            event_queue.pop();\n            sweep_x = e.x;\n\n            if(e.id >= 0) {\n                add_point(e.id);\n            } else if(valid[-e.id]) {\n                remove_arc(e.it);\n            }\n        }\n\n        return edges;\n    }\n\n    const vector<pair<int, int>>& get_edges() const { return edges; }\n};\n\n#endif  // VORONOI_HPP\n"
  },
  {
    "path": "graph/bcc.hpp",
    "content": "#include <bits/stdc++.h>\n\nusing namespace std;\n\nclass biconnected_components {\n  private:\n    vector<int> low, disc;\n\n    void tarjan(int u, int pr, int &dfs_time, vector<pair<int, int>> &st) {\n        low[u] = disc[u] = ++dfs_time;\n\n        int child_cnt = 0;\n        for(int v: adj[u]) {\n            if(v != pr) {\n                if(disc[v] == -1) {\n                    st.push_back({u, v});\n                    tarjan(v, u, dfs_time, st);\n                    child_cnt++;\n                    low[u] = min(low[u], low[v]);\n\n                    if((pr == -1 && child_cnt > 1) ||\n                       (pr != -1 && disc[u] <= low[v])) {\n                        vector<pair<int, int>> curr = {make_pair(u, v)};\n                        while(st.back() != make_pair(u, v)) {\n                            curr.push_back(st.back());\n                            st.pop_back();\n                        }\n\n                        st.pop_back();\n                        if(curr.size() == 1) {\n                            bridges.push_back(curr.back());\n                        } else {\n                            bcc.push_back(curr);\n                        }\n                    }\n                } else if(disc[v] < disc[u]) {\n                    low[u] = min(low[u], disc[v]);\n                    st.push_back({u, v});\n                }\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<vector<int>> adj;\n    vector<vector<pair<int, int>>> bcc;\n    vector<pair<int, int>> bridges;\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    void init(int _n) {\n        n = _n;\n        adj.assign(n + 1, {});\n    }\n\n    void compute_bcc() {\n        bcc.clear();\n        bridges.clear();\n        low.assign(n + 1, -1);\n        disc.assign(n + 1, -1);\n\n        int dfs_time = 0;\n        for(int i = 0; i < n; i++) {\n            if(disc[i] == -1) {\n                vector<pair<int, int>> st;\n                tarjan(i, -1, dfs_time, st);\n                if(!st.empty()) {\n                    if(st.size() == 1) {\n                        bridges.push_back(st.back());\n                    } else {\n                        bcc.push_back(st);\n                    }\n                    st.clear();\n                }\n            }\n        }\n    }\n};\n\n// int n, m;\n// biconnected_components bcc;\n// void read() {\n//     cin >> n >> m;\n//     bcc.init(n);\n//     for(int i = 0; i < m; i++) {\n//         int u, v;\n//         cin >> u >> v;\n//         bcc.add_edge(u, v);\n//     }\n// }\n"
  },
  {
    "path": "graph/bipartite_coloring.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/graph/hopcroft_karp.hpp>\nusing namespace std;\n\nstruct Edge {\n    int u, v, idx;\n    Edge(int _u = 0, int _v = 0, int _idx = 0) : u(_u), v(_v), idx(_idx) {}\n};\n\nclass BipartiteColoring {\n  private:\n    vector<vector<pair<Edge, int>>> edges_for_ver;\n    vector<bool> used;\n    vector<vector<pair<int, int>>> adj;\n    vector<int> memory_m;\n\n    template<class T>\n    static void make_larger_if_needed(vector<T>& v, int size) {\n        if(v.size() < size) {\n            v.resize(size);\n        }\n    }\n\n    pair<vector<Edge>, vector<Edge>> partition_edges_euler(\n        const vector<Edge>& edges, const vector<int>& vers, int n\n    ) {\n        make_larger_if_needed(adj, 2 * n);\n        make_larger_if_needed(memory_m, edges.size());\n\n        for(int v: vers) {\n            adj[v].clear();\n            adj[v + n].clear();\n        }\n\n        for(int ei = 0; ei < (int)edges.size(); ei++) {\n            auto e = edges[ei];\n            adj[e.u].push_back({e.v + n, ei});\n            adj[e.v + n].push_back({e.u, ei});\n            memory_m[ei] = 0;\n        }\n\n        function<void(int, vector<Edge>&, vector<Edge>&)> dfs =\n            [&](int v, vector<Edge>& subgraph_0, vector<Edge>& subgraph_1) {\n                while(!adj[v].empty()) {\n                    auto [u, ei] = adj[v].back();\n                    adj[v].pop_back();\n                    if(memory_m[ei] == 1) {\n                        continue;\n                    }\n                    memory_m[ei] = 1;\n                    dfs(u, subgraph_0, subgraph_1);\n                    if(v < n) {\n                        subgraph_0.push_back(edges[ei]);\n                    } else {\n                        subgraph_1.push_back(edges[ei]);\n                    }\n                    break;\n                }\n            };\n\n        vector<Edge> subgraph_0, subgraph_1;\n        for(int v: vers) {\n            while(!adj[v].empty()) {\n                dfs(v, subgraph_0, subgraph_1);\n            }\n        }\n\n        return {subgraph_0, subgraph_1};\n    }\n\n    vector<Edge> hopcroft_one_colour(\n        const vector<Edge>& edges, int n, vector<vector<Edge>>& answer\n    ) {\n        make_larger_if_needed(edges_for_ver, n);\n        make_larger_if_needed(used, (int)edges.size());\n\n        for(int i = 0; i < n; i++) {\n            edges_for_ver[i].clear();\n        }\n        for(int i = 0; i < (int)edges.size(); i++) {\n            used[i] = false;\n        }\n\n        HopcroftKarp bm(n, n);\n        for(int i = 0; i < (int)edges.size(); i++) {\n            auto e = edges[i];\n            bm.add_edge(e.u, e.v);\n            edges_for_ver[e.u].push_back({e, i});\n        }\n\n        int max_match = bm.max_matching();\n        assert(max_match == n);\n\n        vector<Edge> assigned;\n        vector<pair<int, int>> matches = bm.get_matching();\n        for(auto [u, v]: matches) {\n            for(auto [e, ei]: edges_for_ver[u]) {\n                if(e.v == v && !used[ei]) {\n                    used[ei] = true;\n                    assigned.push_back(e);\n                    break;\n                }\n            }\n        }\n\n        vector<Edge> new_edges;\n        for(int i = 0; i < (int)edges.size(); i++) {\n            if(!used[i]) {\n                new_edges.push_back(edges[i]);\n            }\n        }\n\n        answer.push_back(assigned);\n        return new_edges;\n    }\n\n    // We don't actually use this function as it's actually slower than the\n    // above one.\n    vector<Edge> good_worst_case_one_colour(\n        const vector<Edge>& _edges, int n, int original_m,\n        vector<vector<Edge>>& answer\n    ) {\n        static vector<int> memory_m;\n        make_larger_if_needed(memory_m, original_m);\n\n        int m = _edges.size();\n        int d = m / n;\n\n        int l = 0;\n        while((1 << l) <= m) {\n            l++;\n        }\n\n        int alpha = (1 << l) / d;\n        int beta = (1 << l) - d * alpha;\n\n        vector<Edge> edges = _edges;\n        vector<int> multiplicity(edges.size(), alpha);\n        for(int i = 0; i < m; i++) {\n            auto& e = edges[i];\n            memory_m[e.idx] = i;\n        }\n\n        for(int i = 0; i < n; i++) {\n            edges.push_back(Edge(i, i, -1));\n            multiplicity.push_back(beta);\n        }\n\n        vector<int> vers(n);\n        iota(vers.begin(), vers.end(), 0);\n        while(l--) {\n            vector<Edge> new_edges;\n            for(int i = 0; i < (int)edges.size(); i++) {\n                if(multiplicity[i] % 2) {\n                    new_edges.push_back(edges[i]);\n                }\n                multiplicity[i] /= 2;\n            }\n\n            auto [subgraph_0, subgraph_1] =\n                partition_edges_euler(new_edges, vers, n);\n\n            int cnt0 = 0, cnt1 = 0;\n            for(auto& e: subgraph_0) {\n                if(e.idx == -1) {\n                    cnt0++;\n                }\n            }\n\n            for(auto& e: subgraph_1) {\n                if(e.idx == -1) {\n                    cnt1++;\n                }\n            }\n\n            if(cnt0 > cnt1) {\n                swap(subgraph_0, subgraph_1);\n            }\n\n            for(int i = 0; i < (int)subgraph_0.size(); i++) {\n                auto& e = subgraph_0[i];\n                if(e.idx == -1) {\n                    multiplicity[m + e.u] += 1;\n                } else {\n                    int multiplicity_idx = memory_m[e.idx];\n                    multiplicity[multiplicity_idx] += 1;\n                }\n            }\n        }\n\n        vector<Edge> answer_edges, subgraph_rest;\n        for(int i = 0; i < m; i++) {\n            auto& e = edges[i];\n            if(multiplicity[i]) {\n                answer_edges.push_back(e);\n            } else {\n                subgraph_rest.push_back(e);\n            }\n        }\n\n        answer.push_back(answer_edges);\n        return subgraph_rest;\n    }\n\n  public:\n    int euler_colour(\n        const vector<Edge>& edges, int n, int m, vector<vector<Edge>>& answer\n    ) {\n        static vector<int> memory;\n        make_larger_if_needed(memory, n);\n\n        vector<int> vers, _vers;\n        for(auto e: edges) {\n            _vers.push_back(e.u);\n            _vers.push_back(e.v);\n        }\n\n        int max_degree = 0;\n        for(int v: _vers) {\n            memory[v] = -1;\n        }\n        for(int v: _vers) {\n            if(memory[v] == -1) {\n                vers.push_back(v);\n                memory[v] = 0;\n            }\n        }\n        for(auto e: edges) {\n            memory[e.u]++;\n            max_degree = max(max_degree, memory[e.u]);\n        }\n\n        if(max_degree == 0) {\n            return 0;\n        }\n        if(max_degree == 1) {\n            answer.push_back({});\n            for(auto e: edges) {\n                answer.back().push_back(e);\n            }\n            return 1;\n        }\n\n        if(max_degree % 2 == 1) {\n            auto subgraph = hopcroft_one_colour(edges, n, answer);\n            // Uncomment if we want something that is good in worst case.\n            // auto subgraph = good_worst_case_one_colour(edges, n, m, answer);\n            return 1 + euler_colour(subgraph, n, m, answer);\n        }\n\n        auto [subgraph_0, subgraph_1] =\n            partition_edges_euler(edges, vers, n);\n        int colour_num_subgraph_0 = euler_colour(subgraph_0, n, m, answer);\n\n        int d = max_degree, q = 0;\n        while((1 << q) < (max_degree / 2)) {\n            q++;\n        }\n        int to_remove_count = (1 << q) - (max_degree / 2);\n        if(to_remove_count > 0 && colour_num_subgraph_0 >= to_remove_count) {\n            for(int i = answer.size() - 1; i >= answer.size() - to_remove_count;\n                i--) {\n                for(auto& e: answer[i]) {\n                    subgraph_1.push_back(e);\n                }\n            }\n            answer.erase(answer.end() - to_remove_count, answer.end());\n        }\n\n        int colour_num_subgraph_1 = euler_colour(subgraph_1, n, m, answer);\n        return colour_num_subgraph_0 + colour_num_subgraph_1;\n    }\n};\n"
  },
  {
    "path": "graph/bipartite_matching.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass BipartiteMatching {\n  private:\n    int n, m, visited_timer;\n    vector<int> visited;\n\n    bool try_kuhn(int u) {\n        if(visited[u] == visited_timer) {\n            return false;\n        }\n\n        visited[u] = visited_timer;\n        for(int v: adj[u]) {\n            if(match[v] == -1 || try_kuhn(match[v])) {\n                match[v] = u;\n                inv_match[u] = v;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    int pre_match() {\n        int matching_size = 0;\n        for(int u = 0; u < n; u++) {\n            if(inv_match[u] == -1) {\n                for(int v: adj[u]) {\n                    if(match[v] == -1) {\n                        matching_size++;\n                        match[v] = u;\n                        inv_match[u] = v;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return matching_size;\n    }\n\n  public:\n    vector<int> match, inv_match;\n    vector<vector<int>> adj;\n\n    BipartiteMatching(int _n, int _m = -1) : n(_n), m(_m == -1 ? _n : _m) {\n        adj.assign(n, vector<int>());\n        clear(false);\n    }\n\n    void clear(bool clear_adj = true) {\n        match.assign(m, -1);\n        inv_match.assign(n, -1);\n\n        visited_timer = 0;\n        visited.assign(n, 0);\n        if(clear_adj) {\n            adj.assign(n, vector<int>());\n        }\n    }\n\n    void add_edge(int u, int v) { adj[u].push_back(v); }\n\n    bool match_vertex(int u) {\n        if(inv_match[u] != -1) {\n            return false;\n        }\n\n        visited_timer++;\n        return try_kuhn(u);\n    }\n\n    int max_matching(bool shuffle_edges = false, bool pre_matching = false) {\n        if(shuffle_edges) {\n            for(int i = 0; i < n; i++) {\n                shuffle(\n                    adj[i].begin(), adj[i].end(),\n                    mt19937(\n                        chrono::steady_clock::now().time_since_epoch().count()\n                    )\n                );\n            }\n        }\n\n        int ans = 0;\n        if(pre_matching) {\n            ans += pre_match();\n        }\n\n        for(int i = 0; i < n; i++) {\n            ans += match_vertex(i);\n        }\n\n        return ans;\n    }\n\n    vector<pair<int, int>> get_matching() {\n        vector<pair<int, int>> res;\n        for(int i = 0; i < m; i++) {\n            if(match[i] != -1) {\n                res.emplace_back(match[i], i);\n            }\n        }\n        return res;\n    }\n};\n"
  },
  {
    "path": "graph/dijkstra_vlog.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/data_structures/heap.hpp>\n\nusing namespace std;\n\ntemplate<typename T>\nvector<T> dijkstra(int src, const vector<vector<pair<int, T>>>& adj) {\n    static auto cmp_min = [](int a, int b) -> bool { return a > b; };\n\n    int n = adj.size();\n    vector<T> dist(n, numeric_limits<T>::max());\n    vector<int> pq_node(n, -1);\n    vector<int> pq_node_to_ver(n, -1);\n    Heap<T, +cmp_min> pq;\n\n    function<void(int, T)> update = [&](int u, T d) {\n        dist[u] = min(dist[u], d);\n        if(pq_node[u] == -1) {\n            pq_node[u] = pq.push(dist[u]);\n            pq_node_to_ver[pq_node[u]] = u;\n        } else {\n            pq.update(pq_node[u], dist[u]);\n        }\n    };\n\n    update(src, 0);\n    while(!pq.empty()) {\n        int u = pq_node_to_ver[pq.top_node()];\n        pq.pop();\n\n        for(auto [v, w]: adj[u]) {\n            update(v, dist[u] + w);\n        }\n    }\n\n    return dist;\n}\n"
  },
  {
    "path": "graph/directed_cactus.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass DirectedCactus {\n  private:\n    int n;\n    vector<vector<int>> adj;\n    vector<int> nxt, jump, dep, in_time, out_time;\n\n    void dfs(int u, int &dfs_time, vector<bool> &used, vector<int> &buff) {\n        used[u] = true;\n        in_time[u] = dfs_time++;\n        buff.push_back(u);\n        for(int v: adj[u]) {\n            if(!used[v]) {\n                dep[v] = dep[u] + 1;\n                dfs(v, dfs_time, used, buff);\n            }\n        }\n        out_time[u] = dfs_time - 1;\n    }\n\n  public:\n    DirectedCactus() {\n        n = 0;\n        nxt.clear();\n    }\n    DirectedCactus(vector<int> _nxt) { init(_nxt); }\n\n    void init(vector<int> _nxt) {\n        nxt = _nxt;\n        n = nxt.size();\n        in_time.resize(n);\n        out_time.resize(n);\n        jump.resize(n);\n\n        adj.assign(n, {});\n        for(int i = 0; i < n; i++) {\n            adj[nxt[i]].push_back(i);\n        }\n\n        int dfs_time = 0;\n        vector<bool> used(n, false);\n        dep.assign(n, 0);\n        for(int i = 0; i < n; i++) {\n            if(!used[i]) {\n                vector<int> buff;\n\n                int root = i;\n                while(!used[root]) {\n                    used[root] = true;\n                    buff.push_back(root);\n                    root = nxt[root];\n                }\n\n                for(int u: buff) {\n                    used[u] = false;\n                }\n                buff.clear();\n\n                dfs(root, dfs_time, used, buff);\n                for(int u: buff) {\n                    jump[u] = nxt[root];\n                }\n            }\n        }\n    }\n\n    int distance(int from, int to) {\n        if(in_time[to] <= in_time[from] && out_time[from] <= out_time[to]) {\n            return dep[from] - dep[to];\n        }\n\n        int to_add = dep[from] + 1;\n        from = jump[from];\n        if(in_time[to] <= in_time[from] && out_time[from] <= out_time[to]) {\n            return dep[from] - dep[to] + to_add;\n        }\n        return -1;\n    }\n};\n"
  },
  {
    "path": "graph/dsu.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass DSU {\n  public:\n    int n;\n    vector<int> par;\n    vector<int> sz;\n\n    DSU(int _n = 0) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        par.assign(n + 1, 0);\n        sz.assign(n + 1, 0);\n        for(int i = 0; i <= n; i++) {\n            par[i] = i;\n            sz[i] = 1;\n        }\n    }\n\n    int root(int u) { return par[u] = ((u == par[u]) ? u : root(par[u])); }\n    bool connected(int x, int y) { return root(x) == root(y); }\n\n    int unite(int x, int y) {\n        x = root(x), y = root(y);\n        if(x == y) {\n            return x;\n        }\n        if(sz[x] > sz[y]) {\n            swap(x, y);\n        }\n        par[x] = y;\n        sz[y] += sz[x];\n        return y;\n    }\n\n    vector<vector<int>> components() {\n        vector<vector<int>> comp(n + 1);\n        for(int i = 0; i <= n; i++) {\n            comp[root(i)].push_back(i);\n        }\n        return comp;\n    }\n};\n"
  },
  {
    "path": "graph/eppstein_shortest_paths.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/data_structures/meldable_heap.hpp>\nusing namespace std;\n\ntemplate<class T = int>\nclass EppsteinShortestPaths {\n  private:\n    const T inf = numeric_limits<T>::max() / 2;\n\n    struct Edge {\n        int u, v;\n        T w;\n        Edge(int _u = 0, int _v = 0, T _w = 0) : u(_u), v(_v), w(_w) {}\n    };\n\n    pair<vector<T>, vector<int>> build_dijkstra_tree(int t) {\n        vector<T> dist(n, inf);\n\n        priority_queue<pair<T, int>, vector<pair<T, int>>, greater<>> pq;\n        dist[t] = 0;\n        pq.emplace(0, t);\n\n        while(!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n            if(d != dist[u]) {\n                continue;\n            }\n\n            for(auto [v, idx]: rev_adj[u]) {\n                T nd = d + edges[idx].w;\n                if(nd < dist[v]) {\n                    dist[v] = nd;\n                    pq.emplace(nd, v);\n                }\n            }\n        }\n\n        vector<int> tree(n, -1);\n        for(int u = 0; u < n; u++) {\n            for(auto [v, idx]: adj[u]) {\n                if(dist[u] == dist[v] + edges[idx].w) {\n                    tree[u] = idx;\n                    break;\n                }\n            }\n        }\n\n        return {dist, tree};\n    }\n\n    vector<int> topsort(const vector<int>& tree) {\n        vector<int> deg(n, 0);\n        for(int u = 0; u < n; u++) {\n            if(tree[u] != -1) {\n                deg[edges[tree[u]].v]++;\n            }\n        }\n\n        queue<int> q;\n        for(int u = 0; u < n; u++) {\n            if(deg[u] == 0) {\n                q.push(u);\n            }\n        }\n\n        vector<int> order;\n        while(!q.empty()) {\n            int u = q.front();\n            q.pop();\n            order.push_back(u);\n\n            if(tree[u] != -1) {\n                int v = edges[tree[u]].v;\n                deg[v]--;\n                if(deg[v] == 0) {\n                    q.push(v);\n                }\n            }\n        }\n\n        return order;\n    }\n\n  public:\n    int n;\n    vector<vector<pair<int, int>>> adj;\n    vector<vector<pair<int, int>>> rev_adj;\n    vector<Edge> edges;\n\n    void init(int _n) {\n        n = _n;\n        edges.clear();\n        adj.assign(n, {});\n        rev_adj.assign(n, {});\n    }\n\n    EppsteinShortestPaths(int n = 0) { init(n); }\n\n    int add_edge(int u, int v, T w, bool directed = true) {\n        int idx = edges.size();\n        edges.emplace_back(u, v, w);\n        adj[u].emplace_back(v, idx);\n        rev_adj[v].emplace_back(u, idx);\n\n        if(!directed) {\n            edges.emplace_back(v, u, w);\n            adj[v].emplace_back(u, idx + 1);\n            rev_adj[u].emplace_back(v, idx + 1);\n        }\n\n        return idx;\n    }\n\n    vector<T> get_k_shortest_paths(int s, int t, int k) {\n        auto dist_and_tree = build_dijkstra_tree(t);\n        auto dist = dist_and_tree.first;\n        auto tree = dist_and_tree.second;\n\n        if(dist[s] == inf || k <= 0) {\n            return vector<T>();\n        }\n\n        vector<MeldableHeap<pair<T, int>>> heaps(n);\n        for(int u = 0; u < n; u++) {\n            for(auto& [v, idx]: adj[u]) {\n                if(tree[u] == idx) {\n                    continue;\n                }\n\n                T cost = edges[idx].w + dist[v] - dist[u];\n                heaps[u].push({cost, v});\n            }\n        }\n\n        auto order = topsort(tree);\n        reverse(order.begin(), order.end());\n        for(int u: order) {\n            if(tree[u] != -1) {\n                int par = edges[tree[u]].v ^ edges[tree[u]].u ^ u;\n                heaps[u] = heaps[u].merge(heaps[par]);\n            }\n        }\n\n        vector<T> ans = {dist[s]};\n        if(heaps[s].empty()) {\n            return ans;\n        }\n\n        priority_queue<\n            pair<T, MeldableHeap<pair<T, int>>>,\n            vector<pair<T, MeldableHeap<pair<T, int>>>>, greater<>>\n            pq;\n        pq.emplace(dist[s] + heaps[s].top().first, heaps[s].copy());\n\n        while(!pq.empty() && (int)ans.size() < k) {\n            auto [d, meld_heap] = pq.top();\n            pq.pop();\n            ans.push_back(d);\n\n            auto [head, left_heap, right_heap] = meld_heap.trio();\n            if(!left_heap.empty()) {\n                pq.emplace(d - head.first + left_heap.top().first, left_heap);\n            }\n            if(!right_heap.empty()) {\n                pq.emplace(d - head.first + right_heap.top().first, right_heap);\n            }\n\n            int v = head.second;\n            if(!heaps[v].empty()) {\n                pq.emplace(d + heaps[v].top().first, heaps[v].copy());\n            }\n        }\n\n        return ans;\n    }\n};\n"
  },
  {
    "path": "graph/eulerian_paths.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// This implementation find cnt_odd_vertices / 2 eulerian paths that cover\n// all edges of the graph. The way to use it is to create an object and\n// incrementally add edges to it. Then, call find_paths() to get the paths.\n// If the number of paths is 1, we have either a cycle or a path.\n//\n// Tested on:\n// https://codeforces.com/problemsets/acmsguru/problem/99999/101\n// https://codesprintla24.kattis.com/contests/codesprintla24open/problems/catbusplan\n\nclass EulerianPaths {\n  private:\n    void dfs(int u, vector<int>& path, vector<bool>& used, vector<int>& po) {\n        for(; po[u] < (int)adj[u].size();) {\n            int idx = po[u]++;\n            if(!used[adj[u][idx].second >> 1]) {\n                used[adj[u][idx].second >> 1] = true;\n                dfs(adj[u][idx].first, path, used, po);\n                path.push_back(adj[u][idx].second);\n            }\n        }\n    }\n\n  public:\n    int n, m;\n    vector<int> deg;\n    vector<vector<pair<int, int>>> adj;\n    vector<pair<int, int>> edges;\n\n    EulerianPaths(int _n = 0) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        m = 0;\n        adj.assign(n + 1, {});\n        deg.assign(n + 1, 0);\n        edges.clear();\n    }\n\n    int add_edge(int u, int v) {\n        adj[u].push_back({v, m * 2});\n        adj[v].push_back({u, m * 2 + 1});\n        edges.push_back({u, v});\n        deg[u]++;\n        deg[v]++;\n        m++;\n\n        return edges.size() - 1;\n    }\n\n    vector<vector<int>> find_paths() {\n        vector<bool> used(m, false);\n        vector<int> po(n + 1, 0);\n\n        vector<int> odd_vertices;\n        for(int i = 0; i <= n; i++) {\n            if(deg[i] % 2 == 1) {\n                odd_vertices.push_back(i);\n            }\n        }\n\n        int total_edges = m;\n        for(int i = 0; i < (int)odd_vertices.size() / 2; i++) {\n            int u = odd_vertices[2 * i], v = odd_vertices[2 * i + 1];\n            adj[u].push_back({v, 2 * total_edges});\n            adj[v].push_back({u, 2 * total_edges + 1});\n            total_edges++;\n            used.push_back(false);\n            edges.push_back({u, v});\n        }\n\n        vector<vector<int>> paths;\n        for(int u = 0; u <= n; u++) {\n            if(!adj[u].empty()) {\n                vector<int> path;\n                dfs(u, path, used, po);\n                if(!path.empty()) {\n                    // Rotate the path so that we always start with a fake edge\n                    // if there is at least one.\n                    auto it = find_if(path.begin(), path.end(), [&](int x) {\n                        return x >= 2 * m;\n                    });\n                    if(it != path.end()) {\n                        rotate(path.begin(), it, path.end());\n                    }\n\n                    vector<int> current_path;\n                    for(int x: path) {\n                        if(x < 2 * m) {\n                            current_path.push_back(x);\n                        } else if(!current_path.empty()) {\n                            paths.push_back(current_path);\n                            current_path.clear();\n                        }\n                    }\n                    if(!current_path.empty()) {\n                        paths.push_back(current_path);\n                    }\n                }\n            }\n        }\n\n        return paths;\n    }\n\n    pair<int, int> get_edge(int edge_i) {\n        if(edge_i & 1) {\n            return edges[edge_i >> 1];\n        } else {\n            return {edges[edge_i >> 1].second, edges[edge_i >> 1].first};\n        }\n    }\n\n    vector<pair<int, int>> get_path_edges(const vector<int>& path) {\n        vector<pair<int, int>> result;\n        for(int edge_i: path) {\n            result.push_back(get_edge(edge_i));\n        }\n        return result;\n    }\n\n    bool is_cycle(const vector<int>& path) {\n        int start = get_edge(path[0]).first;\n        int end = get_edge(path.back()).second;\n        return start == end;\n    }\n};\n"
  },
  {
    "path": "graph/graph.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/graph/dsu.hpp>\nusing namespace std;\n\nclass UndirectedGraph {\n  public:\n    int n, m;\n    vector<vector<int>> adj;\n    vector<pair<int, int>> edges;\n\n    bool maintain_dsu;\n    DSU dsu;\n\n    UndirectedGraph(int _n = 0, bool _maintain_dsu = false) {\n        init(_n, _maintain_dsu);\n    }\n\n    void init(int _n, bool _maintain_dsu = false) {\n        m = 0;\n        n = _n;\n        maintain_dsu = _maintain_dsu;\n        adj.assign(n + 1, {});\n        edges.clear();\n\n        if(maintain_dsu) {\n            dsu.init(n);\n        }\n    }\n\n    void read_edges(int _m, int idx_offset = -1) {\n        for(int i = 0; i < _m; i++) {\n            int u, v;\n            cin >> u >> v;\n            u += idx_offset;\n            v += idx_offset;\n            add_edge(u, v);\n        }\n    }\n\n    void add_edges(const vector<pair<int, int>>& new_edges) {\n        for(auto [u, v]: new_edges) {\n            add_edge(u, v);\n        }\n    }\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        edges.emplace_back(u, v);\n        m++;\n\n        if(maintain_dsu) {\n            dsu.unite(u, v);\n        }\n    }\n\n    DSU& get_dsu() {\n        if(!maintain_dsu) {\n            dsu.init(n);\n            for(auto [u, v]: edges) {\n                dsu.unite(u, v);\n            }\n        }\n\n        return dsu;\n    }\n};\n"
  },
  {
    "path": "graph/hopcroft_karp.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Hopcroft-Karp algorithm for bipartite matching that runs in O(E sqrt(V)).\n// Motivated by this submission: https://judge.yosupo.jp/submission/52112, but\n// adapted to match coding_library/graph/bipartite_matching.cpp.\n\nclass HopcroftKarp {\n  private:\n    int n, m;\n    vector<int> dist;\n\n    bool bfs() {\n        queue<int> q;\n        dist.assign(n, -1);\n        for(int u = 0; u < n; u++) {\n            if(inv_match[u] == -1) {\n                dist[u] = 0;\n                q.push(u);\n            }\n        }\n\n        bool found = false;\n        while(!q.empty()) {\n            int u = q.front();\n            q.pop();\n            for(int v: adj[u]) {\n                int m = match[v];\n                if(m == -1) {\n                    found = true;\n                } else if(dist[m] == -1) {\n                    dist[m] = dist[u] + 1;\n                    q.push(m);\n                }\n            }\n        }\n\n        return found;\n    }\n\n    bool dfs(int u) {\n        for(int v: adj[u]) {\n            int m = match[v];\n            if(m == -1 || (dist[m] == dist[u] + 1 && dfs(m))) {\n                inv_match[u] = v;\n                match[v] = u;\n                return true;\n            }\n        }\n        dist[u] = -1;\n        return false;\n    }\n\n  public:\n    vector<int> match, inv_match;\n    vector<vector<int>> adj;\n\n    HopcroftKarp(int _n, int _m = -1) : n(_n), m(_m == -1 ? _n : _m) {\n        adj.assign(n, vector<int>());\n        clear(false);\n    }\n\n    void clear(bool clear_adj = true) {\n        match.assign(m, -1);\n        inv_match.assign(n, -1);\n        if(clear_adj) {\n            adj.assign(n, vector<int>());\n        }\n    }\n\n    void add_edge(int u, int v) { adj[u].push_back(v); }\n\n    int max_matching(bool shuffle_edges = false) {\n        if(shuffle_edges) {\n            for(int i = 0; i < n; i++) {\n                shuffle(\n                    adj[i].begin(), adj[i].end(),\n                    mt19937(\n                        chrono::steady_clock::now().time_since_epoch().count()\n                    )\n                );\n            }\n        }\n\n        int ans = 0;\n        while(bfs()) {\n            for(int u = 0; u < n; u++) {\n                if(inv_match[u] == -1 && dfs(u)) {\n                    ans++;\n                }\n            }\n        }\n        return ans;\n    }\n\n    vector<pair<int, int>> get_matching() {\n        vector<pair<int, int>> matches;\n        for(int u = 0; u < n; u++) {\n            if(inv_match[u] != -1) {\n                matches.emplace_back(u, inv_match[u]);\n            }\n        }\n        return matches;\n    }\n\n    pair<vector<int>, vector<int>> minimum_vertex_cover() {\n        vector<int> left_cover, right_cover;\n        bfs();\n\n        for(int u = 0; u < n; u++) {\n            if(dist[u] == -1) {\n                left_cover.push_back(u);\n            }\n        }\n\n        for(int v = 0; v < m; v++) {\n            if(match[v] != -1 && dist[match[v]] != -1) {\n                right_cover.push_back(v);\n            }\n        }\n\n        return {left_cover, right_cover};\n    }\n};\n\nusing BipartiteMatching = HopcroftKarp;\n"
  },
  {
    "path": "graph/hungarian_algorithm.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Based on http://e-maxx.ru/algo/assignment_hungary#6 but wrapped in a class\n// and zero-based indexing. Optimizes the assignment so that the cost is\n// minimized. Also make sure that n <= m.\n\ntemplate<class T>\nclass HungarianAlgorithm {\n  private:\n    const T INF = numeric_limits<T>::max() / 2;\n    vector<int> way;\n\n  public:\n    int n, m;\n    vector<vector<T>> cost;\n    vector<int> assignment;\n    vector<T> pot_left, pot_right;\n\n    HungarianAlgorithm(const vector<vector<T>>& a) {\n        n = a.size();\n        m = a[0].size();\n        assert(n <= m);\n\n        cost.assign(n + 1, vector<T>(m + 1));\n        for(int i = 0; i < n; i++) {\n            for(int j = 0; j < m; j++) {\n                cost[i][j] = a[i][j];\n            }\n        }\n\n        pot_left.assign(n + 1, 0);\n        pot_right.assign(m + 1, 0);\n        assignment.assign(m + 1, n);\n        way.assign(m + 1, m);\n\n        for(int i = 0; i < n; i++) {\n            assignment[m] = i;\n            int j0 = m;\n            vector<T> minv(m + 1, INF);\n            vector<bool> used(m + 1, false);\n            do {\n                used[j0] = true;\n                int i0 = assignment[j0], j1 = m;\n                T delta = INF;\n                for(int j = 0; j < m; j++) {\n                    if(!used[j]) {\n                        T cur = cost[i0][j] - pot_left[i0] - pot_right[j];\n                        if(cur < minv[j]) {\n                            minv[j] = cur;\n                            way[j] = j0;\n                        }\n                        if(minv[j] < delta) {\n                            delta = minv[j];\n                            j1 = j;\n                        }\n                    }\n                }\n                for(int j = 0; j <= m; j++) {\n                    if(used[j]) {\n                        pot_left[assignment[j]] += delta;\n                        pot_right[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\n                }\n                j0 = j1;\n            } while(assignment[j0] != n);\n\n            do {\n                int j1 = way[j0];\n                assignment[j0] = assignment[j1];\n                j0 = j1;\n            } while(j0 != m);\n        }\n    }\n\n    T get_cost() {\n        T ans = 0;\n        for(int j = 0; j < m; j++) {\n            ans += cost[assignment[j]][j];\n        }\n        return ans;\n    }\n};\n"
  },
  {
    "path": "graph/maxflow.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nclass MaxFlow {\n  private:\n    struct Edge {\n        T flow, cap;\n        int idx, rev, to;\n        Edge(int _to, int _rev, T _flow, T _cap, int _idx)\n            : to(_to), rev(_rev), flow(_flow), cap(_cap), idx(_idx) {}\n    };\n\n    vector<int> dist, po;\n    int n;\n\n    bool bfs(int s, int t) {\n        fill(dist.begin(), dist.end(), -1);\n        fill(po.begin(), po.end(), 0);\n\n        queue<int> q;\n        q.push(s);\n        dist[s] = 0;\n\n        while(!q.empty()) {\n            int u = q.front();\n            q.pop();\n\n            for(Edge e: adj[u]) {\n                if(dist[e.to] == -1 && e.flow < e.cap) {\n                    dist[e.to] = dist[u] + 1;\n                    q.push(e.to);\n                }\n            }\n        }\n        return dist[t] != -1;\n    }\n\n    T dfs(int u, int t, T fl = inf) {\n        if(u == t) {\n            return fl;\n        }\n\n        for(; po[u] < (int)adj[u].size(); po[u]++) {\n            auto& e = adj[u][po[u]];\n            if(dist[e.to] == dist[u] + 1 && e.flow < e.cap) {\n                T f = dfs(e.to, t, min(fl, e.cap - e.flow));\n                e.flow += f;\n                adj[e.to][e.rev].flow -= f;\n                if(f > 0) {\n                    return f;\n                }\n            }\n        }\n\n        return 0;\n    }\n\n  public:\n    constexpr static T inf = numeric_limits<T>::max();\n\n    MaxFlow(int n = 0) { init(n); }\n\n    vector<vector<Edge>> adj;\n\n    void init(int _n) {\n        n = _n;\n        adj.assign(n + 1, {});\n        dist.resize(n + 1);\n        po.resize(n + 1);\n    }\n\n    void add_edge(int u, int v, T w, int idx = -1) {\n        adj[u].push_back(Edge(v, adj[v].size(), 0, w, idx));\n        adj[v].push_back(Edge(u, adj[u].size() - 1, 0, 0, -1));\n    }\n\n    T flow(int s, int t) {\n        assert(s != t);\n\n        T ret = 0, to_add;\n        while(bfs(s, t)) {\n            while((to_add = dfs(s, t))) {\n                ret += to_add;\n            }\n        }\n\n        return ret;\n    }\n};\n"
  },
  {
    "path": "graph/mincost_circulation.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// In some rare cases, we might want to find the min cost circulation instead of\n// min cost flow, and this is non-trivial in the presence of negative cycles (as\n// we would like to select them up to their capacity). The two common approaches are \n// using cost scaling push relabel, or the network simplex. Some resources to check are:\n//\n//     - https://codeforces.com/blog/entry/104075?#comment-925064\n//     - https://codeforces.com/blog/entry/57018\n//     - https://codeforces.com/blog/entry/94190 (+ regular simplex)\n//\n// Here we use bicsi's implementation, based on brunovsky's blog (last one mentioned), which\n// is fairly clean and works well (and it's easy to recover the answer).\n\ntemplate<typename T>\nclass MinCostCirculation {\n  private:\n    struct Edge {\n        int from, to;\n        T capacity, cost, flow;\n        Edge(int _from, int _to, T _capacity, T _cost, T _flow = 0)\n            : from(_from),\n              to(_to),\n              capacity(_capacity),\n              cost(_cost),\n              flow(_flow) {}\n    };\n\n    int n;\n    vector<Edge> edges;\n    vector<int> pei, depth;\n    vector<T> dual;\n    vector<set<int>> tree;\n\n    void dfs(int node) {\n        for(auto ei: tree[node]) {\n            if(ei == pei[node]) {\n                continue;\n            }\n            int vec = edges[ei].to;\n            dual[vec] = dual[node] + edges[ei].cost;\n            pei[vec] = (ei ^ 1);\n            depth[vec] = 1 + depth[node];\n            dfs(vec);\n        }\n    }\n\n    template<typename CB>\n    void walk(int ei, CB&& cb) {\n        cb(ei);\n        int a = edges[ei].from, b = edges[ei].to;\n        while(a != b) {\n            if(depth[a] > depth[b]) {\n                cb(pei[a] ^ 1), a = edges[pei[a]].to;\n            } else {\n                cb(pei[b]), b = edges[pei[b]].to;\n            }\n        }\n    }\n\n  public:\n    MinCostCirculation(int _n = 0) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        edges.clear();\n        pei.assign(n + 1, -1);\n        depth.assign(n + 1, 0);\n        dual.assign(n + 1, 0);\n        tree.assign(n + 1, set<int>());\n    }\n\n    int size() const { return n; }\n\n    int add_edge(int from, int to, T capacity, T cost) {\n        int id = edges.size();\n        edges.push_back(Edge(from, to, capacity, cost, 0));\n        edges.push_back(Edge(to, from, 0, -cost, 0));\n        return id;\n    }\n\n    T min_circulation() {\n        for(int i = 0; i < n; i++) {\n            int ei = add_edge(n, i, 0, 0);\n            tree[n].insert(ei);\n            tree[i].insert(ei ^ 1);\n        }\n\n        T answer = 0;\n        T flow;\n        int cost, ein, eout, ptr = 0;\n        const int B = 3 * n;\n        for(int z = 0; z < (int)edges.size() / B + 1; z++) {\n            if(!z) {\n                dfs(n);\n            }\n\n            pair<T, int> pin = {0, -1};\n            for(int t = 0; t < B; t++, (++ptr) %= (int)edges.size()) {\n                auto& e = edges[ptr];\n                if(e.flow < e.capacity) {\n                    pin =\n                        min(pin,\n                            make_pair(dual[e.from] + e.cost - dual[e.to], ptr));\n                }\n            }\n\n            tie(cost, ein) = pin;\n            if(cost == 0) {\n                continue;\n            }\n\n            pair<T, int> pout = {edges[ein].capacity - edges[ein].flow, ein};\n            walk(ein, [&](int ei) {\n                pout =\n                    min(pout,\n                        make_pair(edges[ei].capacity - edges[ei].flow, ei));\n            });\n\n            tie(flow, eout) = pout;\n            walk(ein, [&](int ei) {\n                edges[ei].flow += flow, edges[ei ^ 1].flow -= flow;\n            });\n\n            tree[edges[ein].from].insert(ein);\n            tree[edges[ein].to].insert(ein ^ 1);\n            tree[edges[eout].from].erase(eout);\n            tree[edges[eout].to].erase(eout ^ 1);\n\n            answer += flow * cost;\n            z = -1;\n        }\n        return answer;\n    }\n\n    const Edge& get_edge(int id) const { return edges[id]; }\n};\n"
  },
  {
    "path": "graph/mincost_flow.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Based on Ormlis' implementation\n\ntemplate<typename T>\nclass MinCostFlow {\n  private:\n    const static T inf = numeric_limits<T>::max();\n\n    struct Edge {\n        int to, rev;\n        T capacity, cost, flow;\n        Edge(int _to, int _rev, T _capacity, T _cost, T _flow)\n            : to(_to),\n              rev(_rev),\n              capacity(_capacity),\n              cost(_cost),\n              flow(_flow) {}\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n    vector<T> potential;\n    vector<pair<int, int>> parent;\n    vector<pair<T, T>> dist;\n\n    void build_potential(int source) {\n        fill(potential.begin(), potential.end(), inf);\n        potential[source] = 0;\n\n        while(true) {\n            bool any = false;\n            for(int v = 0; v < n; v++) {\n                for(const auto& e: g[v]) {\n                    if(e.capacity != 0 && potential[v] != inf &&\n                       potential[v] + e.cost < potential[e.to]) {\n                        potential[e.to] = potential[v] + e.cost;\n                        any = true;\n                    }\n                }\n            }\n            if(!any) {\n                break;\n            }\n        }\n    }\n\n    bool dijkstra(int source, int sink, T flow_limit, T flow) {\n        fill(dist.begin(), dist.end(), make_pair(inf, flow_limit - flow));\n        dist[source].first = 0;\n\n        priority_queue<pair<T, int>, vector<pair<T, int>>, greater<>> q;\n        q.push({0, source});\n\n        while(!q.empty()) {\n            auto [cur_dist, v] = q.top();\n            q.pop();\n            if(cur_dist > dist[v].first) {\n                continue;\n            }\n\n            for(const auto& e: g[v]) {\n                if(potential[e.to] != inf &&\n                   cur_dist + e.cost - potential[e.to] + potential[v] <\n                       dist[e.to].first &&\n                   e.flow < e.capacity) {\n                    parent[e.to] = {v, e.rev};\n                    dist[e.to] = {\n                        cur_dist + e.cost - potential[e.to] + potential[v],\n                        min(dist[v].second, e.capacity - e.flow)\n                    };\n                    q.push({dist[e.to].first, e.to});\n                }\n            }\n        }\n        return dist[sink].first != inf;\n    }\n\n  public:\n    MinCostFlow(int _n = 0) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        g.assign(n, {});\n        potential.resize(n);\n        parent.resize(n);\n        dist.resize(n);\n    }\n\n    int size() const { return n; }\n\n    int add_edge(int from, int to, T capacity, T cost) {\n        int id = g[from].size();\n        g[from].push_back(\n            Edge(to, g[to].size() + (from == to), capacity, cost, 0)\n        );\n        g[to].push_back(Edge(from, id, 0, -cost, 0));\n        return id;\n    }\n\n    pair<T, T> flow(int source, int sink, T flow_limit = inf) {\n        for(int v = 0; v < n; v++) {\n            for(auto& e: g[v]) {\n                e.flow = 0;\n            }\n        }\n\n        T cost = 0, flow = 0;\n        build_potential(source);\n\n        while(flow < flow_limit && dijkstra(source, sink, flow_limit, flow)) {\n            T delta = dist[sink].second;\n            flow += delta;\n\n            for(int v = sink; v != source; v = parent[v].first) {\n                auto& e = g[parent[v].first][g[v][parent[v].second].rev];\n                cost += e.cost * delta;\n                e.flow += delta;\n                g[v][parent[v].second].flow -= delta;\n            }\n\n            for(int i = 0; i < n; i++) {\n                if(dist[i].first != inf) {\n                    potential[i] += dist[i].first;\n                }\n            }\n        }\n        return {cost, flow};\n    }\n};\n"
  },
  {
    "path": "graph/scc.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass StronglyConnectedComponents {\n  private:\n    vector<bool> visited;\n\n    void dfs1(int u) {\n        visited[u] = true;\n        for(int v: adj[u]) {\n            if(!visited[v]) {\n                dfs1(v);\n            }\n        }\n\n        top_sort.push_back(u);\n    }\n\n    void dfs2(int u) {\n        for(int v: radj[u]) {\n            if(comp[v] == -1) {\n                comp[v] = comp[u];\n                dfs2(v);\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<vector<int>> adj, radj;\n    vector<int> comp, comp_ids, top_sort;\n\n    StronglyConnectedComponents() {}\n    StronglyConnectedComponents(int _n) { init(_n); }\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        radj[v].push_back(u);\n    }\n\n    void init(int _n) {\n        n = _n;\n        comp_ids.clear();\n        top_sort.clear();\n        adj.assign(n, {});\n        radj.assign(n, {});\n    }\n\n    void find_components() {\n        comp.assign(n, -1);\n        visited.assign(n, false);\n\n        for(int i = 0; i < n; i++) {\n            if(!visited[i]) {\n                dfs1(i);\n            }\n        }\n\n        reverse(top_sort.begin(), top_sort.end());\n        for(int u: top_sort) {\n            if(comp[u] == -1) {\n                comp[u] = (int)comp_ids.size();\n                comp_ids.push_back(comp[u]);\n                dfs2(u);\n            }\n        }\n    }\n};\n"
  },
  {
    "path": "graph/st_numbering.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass STNumbering {\n  private:\n    vector<int> low, disc, par, sign;\n    vector<int> preorder;\n    int dfs_time;\n\n    bool tarjan_check(int u, int pr) {\n        low[u] = disc[u] = ++dfs_time;\n        int child_cnt = 0;\n        for(int v: adj[u]) {\n            if(v != pr) {\n                if(disc[v] == -1) {\n                    child_cnt++;\n                    if(!tarjan_check(v, u)) {\n                        return false;\n                    }\n                    low[u] = min(low[u], low[v]);\n                    if(pr != -1 && low[v] >= disc[u]) {\n                        return false;\n                    }\n                } else {\n                    low[u] = min(low[u], disc[v]);\n                }\n            }\n        }\n        if(pr == -1 && child_cnt > 1) {\n            return false;\n        }\n        return true;\n    }\n\n    void tarjan(int u, int pr) {\n        low[u] = disc[u] = ++dfs_time;\n        for(int v: adj[u]) {\n            if(v != pr) {\n                if(disc[v] == -1) {\n                    preorder.push_back(v);\n                    tarjan(v, u);\n                    low[u] = min(low[u], low[v]);\n                    par[v] = u;\n                } else {\n                    low[u] = min(low[u], disc[v]);\n                }\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<vector<int>> adj;\n    vector<int> ordering;\n\n    STNumbering() {}\n    STNumbering(int _n) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        adj.assign(n, {});\n        ordering.clear();\n    }\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    bool find_ordering(int s, int t) {\n        low.assign(n, -1);\n        disc.assign(n, -1);\n        par.assign(n, -1);\n        sign.assign(n, 0);\n        preorder.clear();\n        ordering.clear();\n        dfs_time = 0;\n\n        adj[s].push_back(t);\n        adj[t].push_back(s);\n\n        if(!tarjan_check(t, -1)) {\n            adj[s].pop_back();\n            adj[t].pop_back();\n            return false;\n        }\n\n        for(int i = 0; i < n; i++) {\n            if(disc[i] == -1) {\n                adj[s].pop_back();\n                adj[t].pop_back();\n                return false;\n            }\n        }\n\n        fill(low.begin(), low.end(), -1);\n        fill(disc.begin(), disc.end(), -1);\n        fill(sign.begin(), sign.end(), 0);\n        preorder.clear();\n        dfs_time = 0;\n\n        disc[s] = low[s] = ++dfs_time;\n        sign[disc[s]] = -1;\n        tarjan(t, -1);\n\n        list<int> st_li;\n        vector<list<int>::iterator> it_ver(n + 1);\n\n        st_li.push_back(s);\n        st_li.push_back(t);\n        it_ver[disc[s]] = st_li.begin();\n        it_ver[disc[t]] = next(st_li.begin());\n\n        for(int v: preorder) {\n            if(sign[low[v]] == -1) {\n                it_ver[disc[v]] = st_li.insert(it_ver[disc[par[v]]], v);\n            } else {\n                it_ver[disc[v]] = st_li.insert(next(it_ver[disc[par[v]]]), v);\n            }\n            sign[disc[par[v]]] = -sign[low[v]];\n        }\n\n        ordering.assign(st_li.begin(), st_li.end());\n        adj[s].pop_back();\n        adj[t].pop_back();\n        return true;\n    }\n};\n"
  },
  {
    "path": "graph/two_sat.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass TwoSat {\n  private:\n    vector<bool> visited;\n\n    void dfs1(int u) {\n        visited[u] = true;\n        for(int v: adj[u]) {\n            if(!visited[v]) {\n                dfs1(v);\n            }\n        }\n\n        top_sort.push_back(u);\n    }\n\n    void dfs2(int u) {\n        for(int v: radj[u]) {\n            if(comp[v] == -1) {\n                comp[v] = comp[u];\n                dfs2(v);\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<vector<int>> adj, radj;\n    vector<int> comp, comp_ids, top_sort;\n\n    TwoSat() {}\n    TwoSat(int _n) { init(_n); }\n\n    void init(int _n) {\n        n = _n;\n        comp_ids.clear();\n        top_sort.clear();\n        adj.assign(2 * n, {});\n        radj.assign(2 * n, {});\n    }\n\n    void add_implication(int u, int v, bool neg_u = false, bool neg_v = false) {\n        adj[u << 1 | neg_u].push_back(v << 1 | neg_v);\n        radj[v << 1 | neg_v].push_back(u << 1 | neg_u);\n    }\n\n    pair<bool, vector<bool>> solve() {\n        comp.assign(2 * n, -1);\n        visited.assign(2 * n, false);\n\n        for(int i = 0; i < 2 * n; i++) {\n            if(!visited[i]) {\n                dfs1(i);\n            }\n        }\n\n        reverse(top_sort.begin(), top_sort.end());\n        for(int u: top_sort) {\n            if(comp[u] == -1) {\n                comp[u] = (int)comp_ids.size();\n                comp_ids.push_back(comp[u]);\n                dfs2(u);\n            }\n        }\n\n        vector<bool> assignment(n);\n        for(int i = 0; i < n; i++) {\n            if(comp[i << 1] == comp[i << 1 | 1]) {\n                return {false, {}};\n            }\n\n            assignment[i] = comp[i << 1] > comp[i << 1 | 1];\n        }\n\n        return {true, assignment};\n    }\n};\n"
  },
  {
    "path": "math/gauss_bitset.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<size_t N>\nclass GaussBitset {\n  public:\n    int n_var;\n    vector<bitset<N + 1>> rows;\n    vector<int> where;\n    bool solvable = false;\n\n    GaussBitset(int n_var_) : n_var(n_var_) {}\n\n    void add_equation(const vector<int>& coeffs, int rhs) {\n        bitset<N + 1> row;\n        for(int i = 0; i < n_var; i++) {\n            if(coeffs[i] % 2) {\n                row[i] = 1;\n            }\n        }\n        row[n_var] = rhs % 2;\n        rows.push_back(row);\n    }\n\n    void eliminate() {\n        int n_eq = (int)rows.size();\n        where.assign(n_var, -1);\n        int row = 0;\n        for(int col = 0; col < n_var && row < n_eq; col++) {\n            int sel = -1;\n            for(int i = row; i < n_eq; i++) {\n                if(rows[i][col]) {\n                    sel = i;\n                    break;\n                }\n            }\n            if(sel == -1) {\n                continue;\n            }\n            swap(rows[sel], rows[row]);\n            where[col] = row;\n            for(int i = 0; i < n_eq; i++) {\n                if(i != row && rows[i][col]) {\n                    rows[i] ^= rows[row];\n                }\n            }\n            row++;\n        }\n        solvable = true;\n        for(int i = row; i < n_eq; i++) {\n            if(rows[i][n_var]) {\n                solvable = false;\n                break;\n            }\n        }\n    }\n\n    bool has_solution() const { return solvable; }\n\n    vector<int> free_variables() const {\n        vector<int> fv;\n        for(int v = 0; v < n_var; v++) {\n            if(where[v] == -1) {\n                fv.push_back(v);\n            }\n        }\n        return fv;\n    }\n\n    vector<int> any_solution() const {\n        vector<int> x(n_var, 0);\n        for(int v = 0; v < n_var; v++) {\n            if(where[v] != -1) {\n                x[v] = rows[where[v]][n_var];\n            }\n        }\n        return x;\n    }\n};\n"
  },
  {
    "path": "old_impl/data_structures/implicit_treap.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nrandom_device rd;\nmt19937 mt(rd());\n\nstruct implicit_treap {\n    struct node {\n        int val, sz, priority, lazy, rev, sum;\n        node *l, *r, *par;\n\n        node() {\n            lazy = 0;\n            rev = 0;\n            val = 0;\n            sz = 0;\n            priority = 0;\n            l = NULL;\n            r = NULL;\n            par = NULL;\n        }\n        node(int _val) {\n            val = _val;\n            sum = _val;\n            rev = 0;\n            lazy = 0;\n            sz = 1;\n            priority = mt();\n\n            l = NULL;\n            r = NULL;\n            par = NULL;\n        }\n    };\n\n    typedef node *pnode;\n\n    pnode root;\n    map<int, pnode> position;\n\n    void clear() {\n        root = NULL;\n        position.clear();\n    }\n\n    implicit_treap() { clear(); }\n\n    int size(pnode p) { return p ? p->sz : 0; }\n    void update_size(pnode &p) {\n        if(p) {\n            p->sz = size(p->l) + size(p->r) + 1;\n        }\n    }\n\n    void update_parent(pnode &p) {\n        if(!p) {\n            return;\n        }\n        if(p->l) {\n            p->l->par = p;\n        }\n        if(p->r) {\n            p->r->par = p;\n        }\n    }\n\n    void push(pnode &p) {\n        if(!p) {\n            return;\n        }\n        p->sum += size(p) * p->lazy;\n        p->val += p->lazy;\n\n        if(p->rev) {\n            swap(p->l, p->r);\n        }\n\n        if(p->l) {\n            p->l->lazy += p->lazy;\n            p->l->rev ^= p->rev;\n        }\n        if(p->r) {\n            p->r->lazy += p->lazy;\n            p->r->rev ^= p->rev;\n        }\n\n        p->lazy = 0;\n        p->rev = 0;\n    }\n\n    void reset(pnode &t) {\n        if(t) {\n            t->sum = t->val;\n        }\n    }\n\n    void combine(pnode &t, pnode l, pnode r) {\n        if(!l) {\n            t = r;\n            return;\n        }\n        if(!r) {\n            t = l;\n            return;\n        }\n        t->sum = l->sum + r->sum;\n    }\n\n    void operation(pnode &t) {\n        if(!t) {\n            return;\n        }\n\n        reset(t);\n        push(t->l);\n        push(t->r);\n\n        combine(t, t->l, t);\n        combine(t, t, t->r);\n    }\n\n    void split(pnode t, pnode &l, pnode &r, int k, int add = 0) {\n        if(t == NULL) {\n            l = NULL;\n            r = NULL;\n            return;\n        }\n        push(t);\n\n        int idx = add + size(t->l);\n        if(idx <= k) {\n            split(t->r, t->r, r, k, idx + 1), l = t;\n        } else {\n            split(t->l, l, t->l, k, add), r = t;\n        }\n\n        update_parent(t);\n        update_size(t);\n        operation(t);\n    }\n\n    void merge(pnode &t, pnode l, pnode r) {\n        push(l);\n        push(r);\n\n        if(!l) {\n            t = r;\n            return;\n        }\n        if(!r) {\n            t = l;\n            return;\n        }\n\n        if(l->priority > r->priority) {\n            merge(l->r, l->r, r), t = l;\n        } else {\n            merge(r->l, l, r->l), t = r;\n        }\n\n        update_parent(t);\n        update_size(t);\n        operation(t);\n    }\n\n    void insert(int pos, int val) {\n        if(root == NULL) {\n            pnode to_add = new node(val);\n            root = to_add;\n            position[val] = root;\n            return;\n        }\n\n        pnode l, r, mid;\n        mid = new node(val);\n        position[val] = mid;\n\n        split(root, l, r, pos - 1);\n        merge(l, l, mid);\n        merge(root, l, r);\n    }\n\n    void erase(int qL, int qR) {\n        pnode l, r, mid;\n\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n        merge(root, l, r);\n    }\n\n    int query(int qL, int qR) {\n        pnode l, r, mid;\n\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n\n        int answer = mid->sum;\n\n        merge(r, mid, r);\n        merge(root, l, r);\n\n        return answer;\n    }\n\n    void update(int qL, int qR, int val) {\n        pnode l, r, mid;\n\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n\n        mid->lazy += val;\n\n        merge(r, mid, r);\n        merge(root, l, r);\n    }\n\n    void reverse(int qL, int qR) {\n        pnode l, r, mid;\n\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n\n        mid->rev ^= 1;\n        merge(r, mid, r);\n        merge(root, l, r);\n    }\n\n    void cyclic_shift(int qL, int qR, int k) {\n        if(qL == qR) {\n            return;\n        }\n        k %= (qR - qL + 1);\n\n        pnode l, r, mid, fh, sh;\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n\n        split(mid, fh, sh, (qR - qL + 1) - k - 1);\n        merge(mid, sh, fh);\n\n        merge(r, mid, r);\n        merge(root, l, r);\n    }\n\n    int get_pos(pnode curr, pnode son = nullptr) {\n        if(!son) {\n            if(curr == root) {\n                return size(curr->l);\n            } else {\n                return size(curr->l) + get_pos(curr->par, curr);\n            }\n        }\n\n        if(curr == root) {\n            if(son == curr->l) {\n                return 0;\n            } else {\n                return size(curr->l) + 1;\n            }\n        }\n\n        if(curr->l == son) {\n            return get_pos(curr->par, curr);\n        } else {\n            return get_pos(curr->par, curr) + size(curr->l) + 1;\n        }\n    }\n\n    int get_pos(int value) { return get_pos(position[value]); }\n};\n\nimplicit_treap build(const vector<int> &a) {\n    implicit_treap t;\n    t.clear();\n    for(int i = 0; i < (int)a.size(); i++) {\n        t.insert(i, a[i]);\n    }\n\n    return t;\n}\n"
  },
  {
    "path": "old_impl/data_structures/implicit_treap_basic.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nrandom_device rd;\nmt19937 mt(rd());\n\nstruct implicit_treap {\n    struct node {\n        int sz, mx, val, prior;\n        node *l, *r;\n        node() {\n            sz = 0;\n            mx = 0;\n            val = 0;\n            prior = 0;\n            l = nullptr;\n            r = nullptr;\n        }\n        node(int _val) {\n            val = _val;\n            mx = val;\n            sz = 1;\n            prior = mt();\n            l = nullptr;\n            r = nullptr;\n        }\n    };\n\n    typedef node *pnode;\n\n    int size(pnode v) { return v ? v->sz : 0; }\n    void update_size(pnode &v) {\n        if(v) {\n            v->sz = size(v->l) + size(v->r) + 1;\n        }\n    }\n    void reset(pnode &v) {\n        if(v) {\n            v->mx = v->val;\n        }\n    }\n\n    void combine(pnode &v, pnode l, pnode r) {\n        if(!l) {\n            v = r;\n            return;\n        }\n        if(!r) {\n            v = l;\n            return;\n        }\n\n        v->mx = max(l->mx, r->mx);\n    }\n\n    void operation(pnode &v) {\n        if(!v) {\n            return;\n        }\n\n        reset(v);\n        combine(v, v->l, v);\n        combine(v, v, v->r);\n    }\n\n    void merge(pnode &t, pnode l, pnode r) {\n        if(!l) {\n            t = r;\n            return;\n        }\n        if(!r) {\n            t = l;\n            return;\n        }\n\n        if(l->prior > r->prior) {\n            merge(l->r, l->r, r), t = l;\n        } else {\n            merge(r->l, l, r->l), t = r;\n        }\n\n        update_size(t);\n        operation(t);\n    }\n\n    void split(pnode t, pnode &l, pnode &r, int k, int add = 0) {\n        if(!t) {\n            l = nullptr;\n            r = nullptr;\n            return;\n        }\n\n        int idx = add + size(t->l);\n        if(idx <= k) {\n            split(t->r, t->r, r, k, idx + 1), l = t;\n        } else {\n            split(t->l, l, t->l, k, add), r = t;\n        }\n\n        update_size(t);\n        operation(t);\n    }\n\n    pnode root;\n    implicit_treap() { root = nullptr; }\n\n    void insert(int pos, int val) {\n        if(!root) {\n            pnode nw = new node(val);\n            root = nw;\n            return;\n        }\n\n        pnode l, r, nw = new node(val);\n\n        split(root, l, r, pos - 1);\n        merge(l, l, nw);\n        merge(root, l, r);\n    }\n\n    int query_max(int qL, int qR) {\n        pnode l, r, mid;\n\n        split(root, l, r, qL - 1);\n        split(r, mid, r, qR - qL);\n\n        int ret = mid ? mid->mx : -1;\n\n        merge(r, mid, r);\n        merge(root, l, r);\n\n        return ret;\n    }\n};\n"
  },
  {
    "path": "old_impl/data_structures/max_count_segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct count_max_segment_tree {\n    struct node {\n        int mx, cnt, lazy;\n        node() { mx = -(int)1e9, cnt = 0, lazy = 0; }\n        node(int v) {\n            mx = v;\n            cnt = 1;\n            lazy = 0;\n        }\n    };\n\n    node merge(node a, node b) {\n        node ret = node();\n        ret.mx = max(a.mx, b.mx);\n\n        ret.cnt = 0;\n        if(ret.mx == a.mx) {\n            ret.cnt += a.cnt;\n        }\n        if(ret.mx == b.mx) {\n            ret.cnt += b.cnt;\n        }\n\n        return ret;\n    }\n\n    node tr[MAXN << 2];\n\n    void push(int l, int r, int idx) {\n        if(tr[idx].lazy) {\n            tr[idx].mx += tr[idx].lazy;\n            if(l != r) {\n                tr[2 * idx + 1].lazy += tr[idx].lazy;\n                tr[2 * idx + 2].lazy += tr[idx].lazy;\n            }\n            tr[idx].lazy = 0;\n        }\n    }\n\n    void init(int l, int r, int idx) {\n        if(l == r) {\n            tr[idx] = node(-l);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        init(l, mid, 2 * idx + 1);\n        init(mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    void add(int ql, int qr, int v, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(qr < l || ql > r) {\n            return;\n        }\n\n        if(ql <= l && r <= qr) {\n            tr[idx].lazy += v;\n            push(l, r, idx);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        add(ql, qr, v, l, mid, 2 * idx + 1);\n        add(ql, qr, v, mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    node query(int ql, int qr, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(qr < l || ql > r) {\n            return node();\n        }\n\n        if(ql <= l && r <= qr) {\n            return tr[idx];\n        }\n\n        int mid = (l + r) >> 1;\n        return merge(\n            query(ql, qr, l, mid, 2 * idx + 1),\n            query(ql, qr, mid + 1, r, 2 * idx + 2)\n        );\n    }\n\n    void walk(int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(l == r) {\n            cout << l << \": \"\n                 << \"{\" << tr[idx].mx << \" \" << tr[idx].cnt\n                 << \" lazy=\" << tr[idx].lazy << \"}\"\n                 << \" \";\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        walk(l, mid, 2 * idx + 1);\n        walk(mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n};\n"
  },
  {
    "path": "old_impl/data_structures/merging_segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nstruct node {\n    int sz;\n    node *l, *r;\n\n    node() {\n        sz = 0;\n        l = r = nullptr;\n    }\n    node(int _s) {\n        sz = _s;\n        l = r = nullptr;\n    }\n};\n\ntypedef node *pnode;\n\ninline int size(pnode p) { return p ? p->sz : 0; }\n\ninline void update_size(pnode &p) {\n    if(!p) {\n        return;\n    }\n    p->sz = 1 + size(p->l) + size(p->r);\n}\n\npnode init(int val, int l, int r) {\n    pnode ret = new node(1);\n    if(l == r) {\n        return ret;\n    }\n\n    int mid = (l + r) >> 1;\n    if(val <= mid) {\n        ret->l = init(val, l, mid);\n    } else {\n        ret->r = init(val, mid + 1, r);\n    }\n\n    return ret;\n}\n\npnode merge(pnode l, pnode r) {\n    if(!l) {\n        return r;\n    }\n    if(!r) {\n        return l;\n    }\n\n    l->l = merge(l->l, r->l);\n    l->r = merge(l->r, r->r);\n    l->sz += r->sz;\n\n    return l;\n}\n\npair<pnode, pnode> split(pnode &t, int k) {\n    if(!t) {\n        return {nullptr, nullptr};\n    }\n\n    pair<pnode, pnode> ret, tmp;\n    ret.second = new node();\n\n    int L = size(t->l);\n    if(L < k) {\n        tmp = split(t->r, k - L);\n        ret.second = tmp.second;\n        ret.first = t;\n        ret.first->r = tmp.first;\n    } else {\n        tmp = split(t->l, k);\n        ret.first = tmp.first;\n        ret.second = t;\n        ret.second->l = tmp.second;\n    }\n\n    update_size(ret.first);\n    update_size(ret.second);\n    return ret;\n}\n\nint kth(pnode t, int k, int l, int r) {\n    if(!t) {\n        return -1;\n    }\n    if(l == r) {\n        return l;\n    }\n\n    int mid = (l + r) >> 1, L = size(t->l);\n    if(L < k) {\n        return kth(t->r, k - L, l, mid);\n    } else {\n        return kth(t->l, k, mid + 1, r);\n    }\n}\n"
  },
  {
    "path": "old_impl/data_structures/min_segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define SZ(x) ((int)x.size())\n#define ALL(V) V.begin(), V.end()\n#define L_B lower_bound\n#define U_B upper_bound\n#define pb push_back\n\nusing namespace std;\ntemplate<class T, class T1> int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; }\ntemplate<class T, class T1> int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\n\nstruct segment_tree_min {\n\tstruct node {\n\t\tint mn, pos;\n\t\tnode() {\n\t\t\tmn = (int)1e9;\n\t\t\tpos = -1;\n\t\t} \n\n\t\tnode(int v, int i) {\n\t\t\tmn = v;\n\t\t\tpos = i;\n\t\t}\n\t};\n\n\tnode merge(node a, node b) {\n\t\tnode ret = a;\n\t\tif(chkmin(ret.mn, b.mn)) ret.pos = b.pos;\n\t\treturn ret;\n\t}\n\n\tnode tr[MAXN << 2];\n\n\tvoid init(int l, int r, int idx) {\n\t\tif(l == r) {\n\t\t\ttr[idx] = node();\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tvoid update(int pos, int v, int l, int r, int idx) {\n\t\tif(l == r) {\n\t\t\ttr[idx] = node(v, pos);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(pos <= mid) update(pos, v, l, mid, 2 * idx + 1);\n\t\telse update(pos, v, mid + 1, r, 2 * idx + 2);\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tnode query(int ql, int qr, int l, int r, int idx) {\n\t\tif(ql > r || qr < l) {\n\t\t\treturn node();\n\t\t} \n\n\t\tif(ql <= l && r <= qr) {\n\t\t\treturn tr[idx];\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\treturn merge(query(ql, qr, l, mid, 2 * idx + 1),\n\t\t\t\tquery(ql, qr, mid + 1, r, 2 * idx + 2));\n\t}\n};\n\nvoid read() {\n\n}\n\nvoid solve() {\n\n}\n\nint main() {\n\tios_base::sync_with_stdio(false);\n\tcin.tie(nullptr);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/monotonous_queue.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\ntemplate<class T, class T2> inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; }\ntemplate<class T, class T2> inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; }\nconst int MAXN = (1 << 20);\n\ntemplate<class T>\nstruct monotonous_queue_max\n{\n\tint len, current_position;\n\tdeque<pair<T, int> > Q;\n\n\tmonotonous_queue_max() { Q.clear(); current_position = 0; len = 0; }\n\n\tvoid init(int _l)\n\t{\n\t\tlen = _l;\n\t\tcurrent_position = 0;\n\t\tQ.clear();\n\t}\n\n\tvoid push_back(T x)\n\t{\n\t\twhile(!Q.empty() && current_position - Q.front().second >= len) Q.pop_front();\n\t\twhile(!Q.empty() && x >= Q.back().first) Q.pop_back();\n\t\tQ.push_back({x, current_position++});\n\t}\n\n\tT query()\n\t{\n\t\tif(Q.empty()) return -(T)1e9;\n\t\treturn Q.front().first;\n\t}\n};\n\ntemplate<class T>\nstruct monotonous_queue_min\n{\n\tint len, current_position;\n\tdeque<pair<T, int> > Q;\n\n\tmonotonous_queue_min() { Q.clear(); current_position = 0; len = 0; }\n\n\tvoid init(int _l)\n\t{\n\t\tlen = _l;\n\t\tcurrent_position = 0;\n\t\tQ.clear();\n\t}\n\n\tvoid push_back(T x)\n\t{\n\t\twhile(!Q.empty() && current_position - Q.front().second >= len) Q.pop_front();\n\t\twhile(!Q.empty() && x <= Q.back().first) Q.pop_back();\n\t\tQ.push_back({x, current_position++});\n\t}\n\n\tT query()\n\t{\n\t\tif(Q.empty()) return (T)1e9;\n\t\treturn Q.front().first;\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/persistent_segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct node {\n    int sum;\n    node *l, *r;\n    node() {\n        l = nullptr;\n        r = nullptr;\n        sum = 0;\n    }\n    node(int x) {\n        sum = x;\n        l = nullptr;\n        r = nullptr;\n    }\n};\n\nnode* merge(node* l, node* r) {\n    node* ret = new node(0);\n    ret->sum = l->sum + r->sum;\n    ret->l = l;\n    ret->r = r;\n    return ret;\n}\n\nnode* init(int l, int r) {\n    if(l == r) {\n        return (new node(0));\n    }\n\n    int mid = (l + r) >> 1;\n    return merge(init(l, mid), init(mid + 1, r));\n}\n\nnode* update(int pos, int val, int l, int r, node* nd) {\n    if(pos < l || pos > r) {\n        return nd;\n    }\n    if(l == r) {\n        return (new node(val));\n    }\n\n    int mid = (l + r) >> 1;\n    return merge(\n        update(pos, val, l, mid, nd->l), update(pos, val, mid + 1, r, nd->r)\n    );\n}\n\nint query(int qL, int qR, int l, int r, node* nd) {\n    if(qL <= l && r <= qR) {\n        return nd->sum;\n    }\n    if(qL > r || qR < l) {\n        return 0;\n    }\n\n    int mid = (l + r) >> 1;\n    return query(qL, qR, l, mid, nd->l) + query(qL, qR, mid + 1, r, nd->r);\n}\n\nint get_kth(int k, int l, int r, node* nd) {\n    if(l == r) {\n        return l;\n    }\n\n    int mid = (l + r) >> 1;\n    if(nd->l->sum < k) {\n        return get_kth(k - nd->l->sum, mid + 1, r, nd->r);\n    } else {\n        return get_kth(k, l, mid, nd->l);\n    }\n}\n\nvoid read() {}\n\nnode* t[MAXN];\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/data_structures/persistent_segment_tree_lazy.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\ntemplate<class T, class T2>\ninline void chkmax(T &x, const T2 &y) {\n    if(x < y) {\n        x = y;\n    }\n}\ntemplate<class T, class T2>\ninline void chkmin(T &x, const T2 &y) {\n    if(x > y) {\n        x = y;\n    }\n}\nconst int MAXN = (1 << 20);\n\nint n, q;\nint a[MAXN];\n\nstruct node {\n    int64_t lazy, sum;\n    node *l, *r;\n\n    node() {\n        lazy = sum = 0;\n        l = r = nullptr;\n    }\n    node(int64_t val) {\n        lazy = 0;\n        sum = val;\n        l = r = nullptr;\n    }\n};\n\ntypedef node *pnode;\n\npnode merge(pnode a, pnode b) {\n    pnode ret = new node();\n\n    ret->sum = a->sum + b->sum;\n    ret->l = a;\n    ret->r = b;\n\n    return ret;\n}\n\npnode cop(pnode b) {\n    if(!b) {\n        return nullptr;\n    }\n\n    pnode ret = new node();\n    ret->sum = b->sum;\n    ret->lazy = b->lazy;\n\n    ret->l = b->l;\n    ret->r = b->r;\n    return ret;\n}\n\nvoid push(int l, int r, pnode &ver) {\n    if(!ver->lazy) {\n        return;\n    }\n\n    ver->sum += (r - l + 1) * 1ll * ver->lazy;\n\n    ver->l = cop(ver->l);\n    ver->r = cop(ver->r);\n\n    if(l != r) {\n        ver->l->lazy += ver->lazy;\n        ver->r->lazy += ver->lazy;\n    }\n\n    ver->lazy = 0;\n}\n\npnode init(int l, int r) {\n    if(l == r) {\n        return new node(a[l]);\n    }\n    int mid = (l + r) >> 1;\n    return merge(init(l, mid), init(mid + 1, r));\n}\n\npnode update(int qL, int qR, int val, int l, int r, pnode prv) {\n    push(l, r, prv);\n\n    if(qL <= l && r <= qR) {\n        pnode ret = cop(prv);\n        ret->lazy += val;\n        push(l, r, ret);\n        return ret;\n    }\n\n    if(qL > r || qR < l) {\n        return prv;\n    }\n\n    int mid = (l + r) >> 1;\n    return merge(\n        update(qL, qR, val, l, mid, prv->l),\n        update(qL, qR, val, mid + 1, r, prv->r)\n    );\n}\n\nint64_t query(int qL, int qR, int l, int r, pnode nd) {\n    push(l, r, nd);\n    if(qL > r || qR < l) {\n        return 0;\n    }\n    if(qL <= l && r <= qR) {\n        return nd->sum;\n    }\n\n    int mid = (l + r) >> 1;\n    return query(qL, qR, l, mid, nd->l) + query(qL, qR, mid + 1, r, nd->r);\n}\n\nvoid read() {\n    cin >> n >> q;\n    for(int i = 0; i < n; i++) {\n        cin >> a[i];\n    }\n}\n\npnode root[MAXN];\n\nvoid solve() { root[1] = init(0, n - 1); }\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/data_structures/persistent_treap.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nrandom_device rd;\nmt19937 mt(rd());\n\nstruct persistent_treap\n{\n\tstruct node\n\t{\n\t\tint sz, mx, val;\t\t\n\t\tnode *l, *r;\n\t\tnode() { sz = 0; mx = 0; val = 0; l = nullptr; r = nullptr; }\n\t\tnode(int _val) { val = _val; mx = val; sz = 1; l = nullptr; r = nullptr; }\n\t};\n\n\ttypedef node* pnode;\n\n\tpnode copy_node(pnode prv)\n\t{\n\t\tif(!prv) return nullptr;\n\n\t\tpnode ret = new node();\n\t\tret->l = prv->l;\n\t\tret->r = prv->r;\n\t\tret->val = prv->val;\n\t\tret->sz = prv->sz;\n\t\tret->mx = prv->mx;\n\t\treturn ret;\n\t}\n\n\tint size(pnode v) { return v ? v->sz : 0; }\n\tvoid update_size(pnode &v) { if(v) v->sz = size(v->l) + size(v->r) + 1; }\n\tvoid reset(pnode &v) { if(v) v->mx = v->val; }\n\tbool hey(int a, int b) { return (int)mt() % (a + b) < a; }\n\n\tvoid combine(pnode &v, pnode l, pnode r) \n\t{\n\t\tif(!l) { v = r; return; }\n\t\tif(!r) { v = l; return; }\n\n\t\tv->mx = max(l->mx, r->mx);\n\t}\n\n\tvoid operation(pnode &v) \n\t{  \n\t\tif(!v) return;\n\n\t\treset(v);\n\t\tcombine(v, v->l, v);\n\t\tcombine(v, v, v->r);\n\t}\n\n\tvoid merge(pnode &t, pnode l, pnode r)\n\t{\t\n\t\tif(!l) { t = copy_node(r); return; }\n\t\tif(!r) { t = copy_node(l); return; }\n\n\t\tif(hey(size(l), size(r)))\n\t\t{\n\t\t\tt = copy_node(l);\n\t\t\tmerge(t->r, l->r, r);\n\t\t}\n\t\telse\t\n\t\t{\n\t\t\tt = copy_node(r);\n\t\t\tmerge(t->l, l, r->l);\n\t\t}\n\n\t\tupdate_size(t);\n\t\toperation(t);\n\t}\n\n\tvoid split(pnode t, pnode &l, pnode &r, int k, int add = 0)\n\t{\n\t\tif(!t) { l = nullptr; r = nullptr; return; }\n\n\t\tint idx = add + size(t->l);\n\t\tif(idx <= k)\n\t\t{\n\t\t\tl = copy_node(t);\n\t\t\tsplit(t->r, l->r, r, k, idx + 1);\n\t\t\tupdate_size(l);\n\t\t\toperation(l);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tr = copy_node(t);\n\t\t\tsplit(t->l, l, r->l, k, add);\n\t\t\tupdate_size(r);\n\t\t\toperation(r);\n\t\t}\n\n\t\tupdate_size(t);\n\t\toperation(t);\n\t}\n\n\tpnode root;\n\tpersistent_treap() { root = nullptr; }\n\n\tvoid insert(int pos, int val)\n\t{\n\t\tif(!root)\n\t\t{\n\t\t\tpnode nw = new node(val);\n\t\t\troot = nw;\n\t\t\treturn;\n\t\t}\n\n\t\tpnode l, r, nw = new node(val);\n\n\t\tsplit(root, l, r, pos - 1);\n\t\tmerge(l, l, nw);\n\t\tmerge(root, l, r);\n\t}\n\n\tint query_max(int qL, int qR)\n\t{\n\t\tpnode l, r, mid;\n\n\t\tsplit(root, l, r, qL - 1);\n\t\tsplit(r, mid, r, qR - qL);\n\n\t\tint ret = mid ? mid->mx : -1;\n\n\t\tmerge(r, mid, r);\n\t\tmerge(root, l, r);\n\n\t\treturn ret;\n\t}\n};\n\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/persistent_treap_lazy.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nrandom_device rd;\nmt19937 mt(rd());\n\nstruct persistent_treap\n{\n\tstruct node\n\t{\n\t\tint sz, mx, val, lazy;\t\t\n\t\tnode *l, *r;\n\t\tnode() { sz = 0; mx = 0; lazy = 0; val = 0; l = nullptr; r = nullptr; }\n\t\tnode(int _val) { lazy = 0; val = _val; mx = val; sz = 1; l = nullptr; r = nullptr; }\n\t};\n\n\ttypedef node* pnode;\n\n\tpnode copy_node(pnode prv)\n\t{\n\t\tif(!prv) return nullptr;\n\n\t\tpnode ret = new node();\n\t\tret->l = prv->l;\n\t\tret->r = prv->r;\n\t\tret->val = prv->val;\n\t\tret->sz = prv->sz;\n\t\tret->mx = prv->mx;\n\t\tret->lazy = prv->lazy;\n\t\treturn ret;\n\t}\n\n\tint size(pnode v) { return v ? v->sz : 0; }\n\tvoid update_size(pnode &v) { if(v) v->sz = size(v->l) + size(v->r) + 1; }\n\tvoid reset(pnode &v) { if(v) v->mx = v->val; }\n\tbool hey(int a, int b) { return (int)mt() % (a + b) < a; }\n\n\tvoid push(pnode &t)\n\t{\n\t\tif(t && t->lazy)\n\t\t{\n\t\t\tt->mx += t->lazy;\n\t\t\tt->val += t->lazy;\n\t\t\tif(t->l) t->l = copy_node(t->l), t->l->lazy += t->lazy;\n\t\t\tif(t->r) t->r = copy_node(t->r), t->r->lazy += t->lazy;\n\t\t\tt->lazy = 0;\n\t\t}\n\t}\n\n\tvoid combine(pnode &v, pnode l, pnode r) \n\t{\n\t\tif(!l) { v = r; return; }\n\t\tif(!r) { v = l; return; }\n\n\t\tv->mx = max(l->mx, r->mx);\n\t}\n\n\tvoid operation(pnode &v) \n\t{  \n\t\tif(!v) return;\n\n\t\tpush(v->l);\n\t\tpush(v->r);\n\n\t\treset(v);\n\t\tcombine(v, v->l, v);\n\t\tcombine(v, v, v->r);\n\t}\n\n\tvoid merge(pnode &t, pnode l, pnode r)\n\t{\t\n\t\tpush(l), push(r);\n\n\t\tif(!l) { t = copy_node(r); return; }\n\t\tif(!r) { t = copy_node(l); return; }\n\n\t\tif(hey(size(l), size(r)))\n\t\t{\n\t\t\tt = copy_node(l);\n\t\t\tmerge(t->r, l->r, r);\n\t\t}\n\t\telse\t\n\t\t{\n\t\t\tt = copy_node(r);\n\t\t\tmerge(t->l, l, r->l);\n\t\t}\n\n\t\tupdate_size(t);\n\t\toperation(t);\n\t}\n\n\tvoid split(pnode t, pnode &l, pnode &r, int k, int add = 0)\n\t{\n\t\tpush(t);\n\n\t\tif(!t) { l = nullptr; r = nullptr; return; }\n\n\t\tint idx = add + size(t->l);\n\t\tif(idx <= k)\n\t\t{\n\t\t\tl = copy_node(t);\n\t\t\tsplit(t->r, l->r, r, k, idx + 1);\n\t\t\tupdate_size(l);\n\t\t\toperation(l);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tr = copy_node(t);\n\t\t\tsplit(t->l, l, r->l, k, add);\n\t\t\tupdate_size(r);\n\t\t\toperation(r);\n\t\t}\n\n\t\tupdate_size(t);\n\t\toperation(t);\n\t}\n\n\tpnode root;\n\tpersistent_treap() { root = nullptr; }\n\n\tvoid insert(int pos, int val)\n\t{\n\t\tif(!root)\n\t\t{\n\t\t\tpnode nw = new node(val);\n\t\t\troot = nw;\n\t\t\treturn;\n\t\t}\n\n\t\tpnode l, r, nw = new node(val);\n\n\t\tsplit(root, l, r, pos - 1);\n\t\tmerge(l, l, nw);\n\t\tmerge(root, l, r);\n\t}\n\n\tint query_max(int qL, int qR)\n\t{\n\t\tpnode l, r, mid;\n\n\t\tsplit(root, l, r, qL - 1);\n\t\tsplit(r, mid, r, qR - qL);\n\n\t\tint ret = mid ? mid->mx : -1;\n\n\t\tmerge(r, mid, r);\n\t\tmerge(root, l, r);\n\n\t\treturn ret;\n\t}\n};\n\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 18);\n\nint n, m;\nint a[MAXN];\n\nstruct node {\n\tint sum;\n\tnode() { sum = 0; }\n\tnode(int val) {\n\t\tsum = val;\n\t}\n};\n\nnode merge(node l, node r) {\n\tnode temp;\n\ttemp.sum = l.sum + r.sum;\n\treturn temp;\n}\n\nstruct segment_tree {\n\tnode tr[MAXN << 2];\n\n\tvoid init(int l, int r, int idx) {\n\t\tif(l == r) {\n\t\t\ttr[idx] = node(a[l]);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tvoid update(int pos, int val, int l, int r, int idx) {\n\t\tif(l > pos || r < pos)\n\t\t\treturn;\n\n\t\tif(l == r && l == pos) {\n\t\t\ttr[idx].sum += val;\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tupdate(pos, val, l, mid, 2 * idx + 1);\n\t\tupdate(pos, val, mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tnode query(int qL, int qR, int l, int r, int idx) {\n\t\tif(l > qR || r < qL) {\n\t\t\treturn node();\n\t\t}\n\n\t\tif(qL <= l && r <= qR) {\n\t\t\treturn tr[idx];\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\treturn merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2));\n\t}\n};\n\nvoid read()\n{\n\tcin >> n >> m;\n\tfor(int i = 0; i < n; i++)\n\t\tcin >> a[i];\n}\n\nsegment_tree t;\n\nvoid solve()\n{\n\tt.init(0, n - 1, 0);\n\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\tint l, r;\n\t\tcin >> l >> r;\n\t\tcout << t.query(l, r, 0, n - 1, 0).sum << endl;\n\t}\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_AP.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 18);\n\nint n, m;\nint a[MAXN];\n\nstruct node_ap\n{\n\tint sum, lazy, lazy_ap;\n\t\n\tnode_ap() {sum = 0; lazy = 0; lazy_ap = 0;}\n\tnode_ap(int val)\n\t{\n\t\tsum = val;\n\t\tlazy = 0;\n\t\tlazy_ap = 0;\n\t}\n};\n\nnode_ap temp, broken;\n\nnode_ap merge(node_ap l, node_ap r)\n{\n\ttemp.sum = l.sum + r.sum;\n\ttemp.lazy = 0;\n\ttemp.lazy_ap = 0;\n\treturn temp;\n}\n\nstruct segment_tree_ap\n{\n\tnode_ap tr[4 * MAXN];\n\n\tvoid update(int l, int r, int idx)\n\t{\n\t\tif(tr[idx].lazy)\n\t\t{\n\t\t\ttr[idx].sum += (r - l + 1) * tr[idx].lazy;\n\n\t\t\tif(l != r)\n\t\t\t{\n\t\t\t\ttr[2 * idx + 1].lazy += tr[idx].lazy;\n\t\t\t\ttr[2 * idx + 2].lazy += tr[idx].lazy;\n\t\t\t}\n\n\t\t\ttr[idx].lazy = 0;\n\t\t}\t\n\n\t\tif(tr[idx].lazy_ap)\n\t\t{\n\t\t\tint mid = (l + r) >> 1;\n\t\t\ttr[idx].sum += ((r - l + 1) * (r - l + 2) / 2) * tr[idx].lazy_ap;\n\n\t\t\tif(l != r)\n\t\t\t{\n\t\t\t\ttr[2 * idx + 1].lazy_ap += tr[idx].lazy_ap;\n\t\t\t\ttr[2 * idx + 2].lazy_ap += tr[idx].lazy_ap;\n\t\t\t\ttr[2 * idx + 2].lazy += tr[idx].lazy_ap * (mid - l + 1);\n\t\t\t}\n\n\t\t\ttr[idx].lazy_ap = 0;\n\t\t}\n\t}\n\n\tvoid init(int l, int r, int idx)\n\t{\n\t\tif(l == r)\n\t\t{\n\t\t\ttr[idx] = node_ap(a[l]);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\t\n\t\n\tvoid update(int qL, int qR, int val, int prog, int l, int r, int idx)\n\t{\n\t\tupdate(l, r, idx);\n\n\t\tif(qL > r || l > qR)\n\t\t\treturn;\n\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\ttr[idx].lazy += val + (l - qL) * prog;\n\t\t\ttr[idx].lazy_ap += prog;\n\t\t\tupdate(l, r, idx);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tupdate(qL, qR, val, prog, l, mid, 2 * idx + 1);\n\t\tupdate(qL, qR, val, prog, mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tnode_ap query(int qL, int qR, int l, int r, int idx)\n\t{\n\t\tupdate(l, r, idx);\n\n\t\tif(l > qR || r < qL)\n\t\t\treturn broken;\n\n\t\tif(qL <= l && r <= qR)\n\t\t\treturn tr[idx];\n\n\t\tint mid = (l + r) >> 1;\n\t\treturn merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2));\n\t}                 \n};\n\nvoid read()\n{\n\n}\n\nsegment_tree_ap t;\n\nvoid solve()\n{\n\tt.init(0, n - 1, 0);\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_add_mult.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n//#pragma GCC optimize (\"O3\")\n//#pragma GCC target (\"sse4\")\n\nusing namespace std;\ntemplate<class T, class T2> inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; }\ntemplate<class T, class T2> inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\nconst int mod = (int)1e9 + 7;\n\nstruct node\n{\n\tint sum, lazy, mult;\n\n\tnode() {sum = 0; mult = 1; lazy = 0;}\n\tnode(int val)\n\t{\n\t\tsum = val;\n\t\tlazy = 0;\n\t\tmult = 1;\n\t}\n};\n\nnode temp, broken;\n\nnode merge(node l, node r)\n{\n\ttemp.sum = (l.sum + r.sum) % mod;\n\ttemp.lazy = 0;\n\ttemp.mult = 1;\n\treturn temp;\n}\n\nstruct segment_tree\n{\n\tnode tr[4 * MAXN];\n\n\tvoid push(int l, int r, int idx)\n\t{\n\t\tif(tr[idx].mult != 1)\n\t\t{\n\t\t\ttr[idx].sum = (tr[idx].sum * 1ll * tr[idx].mult) % mod;\n\t\t\ttr[idx].sum %= mod;\n\n\t\t\tif(l != r)\n\t\t\t{\n\t\t\t\ttr[2 * idx + 1].mult = (tr[2 * idx + 1].mult * 1ll * tr[idx].mult) % mod;\n\t\t\t\ttr[2 * idx + 2].mult = (tr[2 * idx + 2].mult * 1ll * tr[idx].mult) % mod;\n\t\t\t\ttr[2 * idx + 1].lazy = (tr[2 * idx + 1].lazy * 1ll * tr[idx].mult) % mod;\n\t\t\t\ttr[2 * idx + 2].lazy = (tr[2 * idx + 2].lazy * 1ll * tr[idx].mult) % mod;\n\t\t\t}\n\n\t\t\ttr[idx].mult = 1;\n\t\t}\n\n\t\tif(tr[idx].lazy)\n\t\t{\n\t\t\ttr[idx].sum += ((r - l + 1) * 1ll * tr[idx].lazy) % mod;\n\t\t\ttr[idx].sum %= mod;\n\n\t\t\tif(l != r)\n\t\t\t{\n\t\t\t\ttr[2 * idx + 1].lazy = (tr[2 * idx + 1].lazy + tr[idx].lazy) % mod;\n\t\t\t\ttr[2 * idx + 2].lazy = (tr[2 * idx + 2].lazy + tr[idx].lazy) % mod;\n\t\t\t}\n\n\t\t\ttr[idx].lazy = 0;\n\t\t}\n\t}\n\n\tvoid init(int l, int r, int idx)\n\t{\n\t\tif(l == r)\n\t\t{\n\t\t\ttr[idx] = node();\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tvoid mult(int qL, int qR, int x, int l, int r, int idx)\n\t{\n\t\tpush(l, r, idx);\n\t\tif(qL > r || l > qR)\n\t\t\treturn;\n\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\ttr[idx].mult = (tr[idx].mult * 1ll * x) % mod;\n\t\t\tpush(l, r, idx);\n\t\t\treturn;\n\t\t}\t\t\n\n\t\tint mid = (l + r) >> 1;\n\t\tmult(qL, qR, x, l, mid, 2 * idx + 1);\n\t\tmult(qL, qR, x, mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\t\n\tvoid add(int qL, int qR, int x, int l, int r, int idx)\n\t{\n\t\tpush(l, r, idx);\n\t\tif(qL > r || l > qR)\n\t\t\treturn;\n\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\ttr[idx].lazy = (tr[idx].lazy + x) % mod;\n\t\t\tpush(l, r, idx);\n\t\t\treturn;\n\t\t}\t\t\n\n\t\tint mid = (l + r) >> 1;\n\t\tadd(qL, qR, x, l, mid, 2 * idx + 1);\n\t\tadd(qL, qR, x, mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tnode query(int qL, int qR, int l, int r, int idx)\n\t{\n\t\tpush(l, r, idx);\n\n\t\tif(l > qR || r < qL)\n\t\t\treturn broken;\n\n\t\tif(qL <= l && r <= qR)\n\t\t\treturn tr[idx];\n\n\t\tint mid = (l + r) >> 1;\n\t\treturn merge(query(qL, qR, l, mid, 2 * idx + 1), query(qL, qR, mid + 1, r, 2 * idx + 2));\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_fast.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct node {\n    int mx;\n    node() { mx = -1e9; }\n    node(int val) { mx = val; }\n};\n\nnode temp;\n\nnode merge(node l, node r) {\n    temp.mx = max(l.mx, r.mx);\n    return temp;\n}\n\nstruct segment_tree {\n    int n;\n    node t[2 * MAXN];\n\n    void init(int sz) {\n        n = sz;\n        for(int i = 0; i < n; i++) {\n            t[i + n] = node();\n        }\n        for(int i = n - 1; i > 0; --i) {\n            t[i] = merge(t[i << 1], t[i << 1 | 1]);\n        }\n    }\n\n    void modify(int p, const node &value) {\n        for(t[p += n] = value; p >>= 1;) {\n            t[p] = merge(t[p << 1], t[p << 1 | 1]);\n        }\n    }\n\n    node query(int l, int r) {\n        node resl, resr;\n        for(l += n, r += n; l < r; l >>= 1, r >>= 1) {\n            if(l & 1) {\n                resl = merge(resl, t[l++]);\n            }\n            if(r & 1) {\n                resr = merge(t[--r], resr);\n            }\n        }\n\n        return merge(resl, resr);\n    }\n};\n\nvoid read() {}\n\nsegment_tree t;\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_lazy_min.cpp",
    "content": "#include <bits/stdc++.h>\n#include <limits>\nusing namespace std;\n\ntemplate<class T>\nclass segment_tree_min {\n  private:\n    static const T max_possible_value = std::numeric_limits<T>::max();\n\n    struct node {\n        T mn;\n        int pos;\n\n        node() {\n            mn = max_possible_value;\n            pos = -1;\n        }\n\n        node(T val, int p) {\n            mn = val;\n            pos = p;\n        }\n    };\n\n    node merge(node l, node r) {\n        node temp;\n        temp.mn = min(l.mn, r.mn);\n        if(l.mn == temp.mn) {\n            temp.pos = l.pos;\n        } else {\n            temp.pos = r.pos;\n        }\n\n        return temp;\n    }\n\n    void push(int l, int r, int idx) {\n        if(lazy[idx]) {\n            tr[idx].mn += lazy[idx];\n\n            if(l != r) {\n                lazy[2 * idx + 1] += lazy[idx];\n                lazy[2 * idx + 2] += lazy[idx];\n            }\n\n            lazy[idx] = 0;\n        }\n    }\n\n    int n;\n    vector<T> lazy;\n    vector<node> tr;\n\n    void init(int l, int r, int idx, const vector<T> &a) {\n        if(l == r) {\n            tr[idx] = node(a[l], l);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        init(l, mid, 2 * idx + 1, a);\n        init(mid + 1, r, 2 * idx + 2, a);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    void update(int qL, int qR, T val, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(qL > r || l > qR) {\n            return;\n        }\n\n        if(qL <= l && r <= qR) {\n            lazy[idx] += val;\n            push(l, r, idx);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        update(qL, qR, val, l, mid, 2 * idx + 1);\n        update(qL, qR, val, mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    node query(int qL, int qR, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(l > qR || r < qL) {\n            return node();\n        }\n\n        if(qL <= l && r <= qR) {\n            return tr[idx];\n        }\n\n        int mid = (l + r) >> 1;\n        return merge(\n            query(qL, qR, l, mid, 2 * idx + 1),\n            query(qL, qR, mid + 1, r, 2 * idx + 2)\n        );\n    }\n\n  public:\n    void init(const vector<T> &a) {\n        n = a.size();\n        tr.resize(4 * n);\n        lazy.assign(4 * n, 0);\n        init(0, n - 1, 0, a);\n    }\n\n    void update(int qL, int qR, int val) {\n        if(qR < qL) {\n            return;\n        }\n        update(qL, qR, val, 0, n - 1, 0);\n    }\n\n    node query(int qL, int qR) {\n        if(qR < qL) {\n            return node();\n        }\n\n        return query(qL, qR, 0, n - 1, 0);\n    }\n};\n\nint n, m;\nvector<int> a;\n\nvoid read() {\n    cin >> n >> m;\n    a.resize(n);\n    for(int i = 0; i < n; i++) {\n        cin >> a[i];\n    }\n}\n\nsegment_tree_min<int> t;\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_lazy_sum.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T>\nclass segment_tree_sum {\n  private:\n    struct node {\n        T sum;\n\n        node() { sum = 0; }\n        node(T val) { sum = val; }\n    };\n\n    node merge(node l, node r) {\n        node temp;\n        temp.sum = l.sum + r.sum;\n        return temp;\n    }\n\n    void push(int l, int r, int idx) {\n        if(lazy[idx]) {\n            tr[idx].sum += lazy[idx] * (r - l + 1);\n\n            if(l != r) {\n                lazy[2 * idx + 1] += lazy[idx];\n                lazy[2 * idx + 2] += lazy[idx];\n            }\n\n            lazy[idx] = 0;\n        }\n    }\n\n    int n;\n    vector<T> lazy;\n    vector<node> tr;\n\n    void init(int l, int r, int idx, const vector<T> &a) {\n        if(l == r) {\n            tr[idx] = node(a[l]);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        init(l, mid, 2 * idx + 1, a);\n        init(mid + 1, r, 2 * idx + 2, a);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    void update(int qL, int qR, T val, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(qL > r || l > qR) {\n            return;\n        }\n\n        if(qL <= l && r <= qR) {\n            lazy[idx] += val;\n            push(l, r, idx);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        update(qL, qR, val, l, mid, 2 * idx + 1);\n        update(qL, qR, val, mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    node query(int qL, int qR, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(l > qR || r < qL) {\n            return node();\n        }\n\n        if(qL <= l && r <= qR) {\n            return tr[idx];\n        }\n\n        int mid = (l + r) >> 1;\n        return merge(\n            query(qL, qR, l, mid, 2 * idx + 1),\n            query(qL, qR, mid + 1, r, 2 * idx + 2)\n        );\n    }\n\n  public:\n    void init(vector<T> a) {\n        n = a.size();\n        tr.resize(4 * n);\n        lazy.assign(4 * n, 0);\n        init(0, n - 1, 0, a);\n    }\n\n    void update(int qL, int qR, int val) {\n        if(qR < qL) {\n            return;\n        }\n        update(qL, qR, val, 0, n - 1, 0);\n    }\n\n    node query(int qL, int qR) {\n        if(qR < qL) {\n            return node();\n        }\n\n        return query(qL, qR, 0, n - 1, 0);\n    }\n};\n\nint n, m;\nvector<int> a;\n\nvoid read() {\n    cin >> n >> m;\n    a.resize(n);\n    for(int i = 0; i < n; i++) {\n        cin >> a[i];\n    }\n}\n\nsegment_tree_sum<int> t;\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_nonzero.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct segment_tree\n{\n\tint ord[4 * MAXN], sum[4 * MAXN];\n\n\tvoid init(int l, int r, int idx) \n\t{  \n\t\tif(l == r)\n\t\t{\n\t\t\tord[idx] = 0;\n\t\t\tsum[idx] = 0; \n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\t\n\t\tif(ord[idx]) sum[idx] = (r - l + 1);\n\t\telse sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2];\n\t}\n\n\tvoid update(int qL, int qR, int val, int l, int r, int idx)\n\t{\n\t\tif(r < qL || l > qR)\n\t\t\treturn;\n\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\tord[idx] += val;\n\t\t\tif(ord[idx] > 0) sum[idx] = (r - l + 1);\n\t\t\telse sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2];\n\t\t\treturn;\n\t\t}\n\t\n\t\tint mid = (l + r) >> 1;\n\t\tupdate(qL, qR, val, l, mid, 2 * idx + 1);\n\t\tupdate(qL, qR, val, mid + 1, r, 2 * idx + 2);\n\n\t\tif(ord[idx] > 0) sum[idx] = (r - l + 1);\n\t\telse sum[idx] = sum[2 * idx + 1] + sum[2 * idx + 2];\n\t}\n};\n\nvoid read()\n{\n\n}\t\n\nsegment_tree t;\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/segment_tree_with_binary_search.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\ntemplate<class T, class T2> inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; }\ntemplate<class T, class T2> inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; }\nconst int MAXN = (1 << 20);\nconst int inf = (int)1e9 + 42;\n\nstruct node\n{\n\tint mn;\n\tnode() { mn = inf; }\n\tnode(int val) { mn = val; }\n};\n\nnode temp, broken;\n\nnode merge(node l, node r)\n{\n\ttemp.mn = min(l.mn, r.mn);\n\treturn temp;\n}\n\nint bound_L[MAXN], bound_R[MAXN];\nstruct segment_tree\n{\n\tnode tr[4 * MAXN];\n\n\tvoid init(int l, int r, int idx)\n\t{\n\t\tbound_L[idx] = l;\n\t\tbound_R[idx] = r;\n\t\tif(l == r)\n\t\t{\n\t\t\ttr[idx] = node(inf);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tvoid update(int pos, int val, int l, int r, int idx)\n\t{\n\t\tif(l > pos || r < pos)\n\t\t\treturn;\n\n\t\tif(l == r && l == pos)\n\t\t{\n\t\t\ttr[idx].mn = val;\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tupdate(pos, val, l, mid, 2 * idx + 1);\n\t\tupdate(pos, val, mid + 1, r, 2 * idx + 2);\n\n\t\ttr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n\t}\n\n\tvoid get_nodes(int qL, int qR, int l, int r, int idx, vector<int> &li)\n\t{\n\t\tif(l > qR || r < qL) return;\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\tli.push_back(idx);\n\t\t\treturn;\n\t\t}\n\n\t\tint mid = (l + r) >> 1;\n\t\tget_nodes(qL, qR, l, mid, 2 * idx + 1, li);\n\t\tget_nodes(qL, qR, mid + 1, r, 2 * idx + 2, li);\n\t}\n\n\tint get_right(int l, int r, int idx, int X)\n\t{\n\t\tif(l == r) return l;\n\t\tint mid = (l + r) >> 1;\n\t\tif(tr[2 * idx + 1].mn <= X) return get_right(l, mid, 2 * idx + 1, X);\n\t\telse return get_right(mid + 1, r, 2 * idx + 2, X);\n\t}\n\n\tint get_left(int l, int r, int idx, int X)\n\t{\n\t\tif(l == r) return l;\n\t\tint mid = (l + r) >> 1;\n\t\tif(tr[2 * idx + 2].mn <= X) return get_left(mid + 1, r, 2 * idx + 2, X);\n\t\telse return get_left(l, mid, 2 * idx + 1, X);\n\t}\n};\n\nint n;\nsegment_tree t;\n\nint get_left(int pos, int val)\n{\n\tvector<int> li;\n\tt.get_nodes(1, pos, 1, n, 0, li);\n\treverse(li.begin(), li.end());\n\n\tfor(int it: li)\n\t\tif(t.tr[it].mn <= val) \n\t\t\treturn t.get_left(bound_L[it], bound_R[it], it, val);\n\n\treturn 0;\n}\n\nint get_right(int pos, int val)\n{\n\tvector<int> li;\n\tt.get_nodes(pos, n, 1, n, 0, li);\n\n\tfor(int it: li)\n\t\tif(t.tr[it].mn <= val) \n\t\t\treturn t.get_right(bound_L[it], bound_R[it], it, val);\n\n\n\treturn n + 1;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/data_structures/treap.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nrandom_device rd;\nmt19937 mt(rd());\n\nstruct node {\n    int sz, prior, value;\n    node *l, *r;\n    node() {\n        value = 0;\n        sz = 0;\n        prior = 0;\n        l = nullptr;\n        r = nullptr;\n    }\n    node(int v) {\n        value = v;\n        sz = 1;\n        prior = mt();\n        l = nullptr;\n        r = nullptr;\n    }\n};\n\ntypedef node *pnode;\n\ninline int size(pnode v) { return v ? v->sz : 0; }\n\nvoid pull(pnode &v) {\n    if(!v) {\n        return;\n    }\n    v->sz = size(v->l) + size(v->r) + 1;\n}\n\nvoid merge(pnode &t, pnode l, pnode r) {\n    if(!l) {\n        t = r;\n        return;\n    }\n    if(!r) {\n        t = l;\n        return;\n    }\n\n    if(l->prior > r->prior) {\n        merge(l->r, l->r, r), t = l;\n    } else {\n        merge(r->l, l, r->l), t = r;\n    }\n\n    pull(t);\n}\n\nvoid split(pnode t, pnode &l, pnode &r, int k) {\n    if(!t) {\n        l = nullptr;\n        r = nullptr;\n        return;\n    }\n\n    if(t->value <= k) {\n        split(t->r, t->r, r, k), l = t;\n    } else {\n        split(t->l, l, t->l, k), r = t;\n    }\n\n    pull(t);\n}\n\nvoid merge_op(pnode &t, pnode l, pnode r) {\n    if(!l) {\n        t = r;\n        return;\n    }\n    if(!r) {\n        t = l;\n        return;\n    }\n\n    if(l->prior < r->prior) {\n        swap(l, r);\n    }\n\n    pnode L, R;\n    split(r, L, R, l->value - mt() % 2);\n    merge_op(l->r, l->r, R);\n    merge_op(l->l, L, l->l);\n\n    t = l;\n    pull(t);\n}\n\nvoid split_sz(pnode t, pnode &l, pnode &r, int k, int add = 0) {\n    if(!t) {\n        l = nullptr;\n        r = nullptr;\n        return;\n    }\n\n    int idx = add + size(t->l);\n    if(idx <= k) {\n        split_sz(t->r, t->r, r, k, idx + 1), l = t;\n    } else {\n        split_sz(t->l, l, t->l, k, add), r = t;\n    }\n\n    pull(t);\n}\n\nvoid read() {}\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/geometry/closest_points.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst double eps = 0.000001;\nconst int inf = (int)1e17 + 42;\n\nstruct point\n{\n\tint x, y;\n\n\tpoint() {x = 0; y = 0;}\n\tpoint(int _x, int _y)\n\t{\n\t\tx = _x;\n\t\ty = _y;\n\t}\n};\n\nbool cmpbyx(point a, point b)\n{\n\tif(a.x == b.x) return a.y < b.y;\n\treturn a.x < b.x;\n}\n\nbool cmpbyy(point a, point b)\n{\n\tif(a.y == b.y) return a.x < b.x;\n\treturn a.y < b.y;\n}\n\nint n;\nint a[MAXN];\n\nvoid read()\n{\n\tcin >> n;\n\tfor(int i = 1; i <= n; i++)\n\t\tcin >> a[i];\n}\n\nvector<point> p;\nint 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); }\n\nint rec(int l, int r)\n{\n\tif(l == r) return inf;\n\n\tint ret, mid = (l + r) >> 1;\n\tdouble d;\n\tret = min(rec(l, mid), rec(mid + 1, r));\n\td = sqrt(ret);\n\n\tvector<point> c;\n\tfor(int i = l; i <= r; i++)\n\t\tif(abs(p[i].x - p[mid].x) <= d)\n\t\t\tc.push_back(p[i]);\n\n\tsort(c.begin(), c.end(), cmpbyy);\n\n\tfor(int i = 0; i < c.size(); i++)\n\t\tfor(int j = i + 1; j < c.size() && (c[j].y - c[i].y) <= d; j++)\n\t\t{\n\t\t\tret = min(ret, dist(c[i], c[j]));\n\t\t\td = sqrt(ret);\n\t\t}\n\t\t\n\treturn ret;\n}\n\nvoid solve()\n{\n\ta[0] = 0;\n\tfor(int i = 1; i <= n; i++)\n\t\ta[i] += a[i - 1];\n\n\tfor(int i = 1; i <= n; i++)\n\t\tp.push_back(point(i, a[i]));\n\n\tsort(p.begin(), p.end(), cmpbyx);\n\n\tint ans = rec(0, n - 1);\n\tcout << ans << endl;\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/geometry/convex_hull.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define double long double\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst double dinf = (double)1e17;\nconst double eps = 0.00000000000001;\n\nstruct point {\n\tdouble x, y;\n\tpoint() {x = 0; y = 0;}\n\tpoint(double _x, double _y) {\n\t\tx = _x;\n\t\ty = _y;\n\t}\n};\n\nbool cmp(point a, point b) {\n\tif(a.x == b.x) return a.y < b.y;\n\treturn a.x < b.x;\n}\n\ndouble slope(point a, point b) {\n\tdouble deltax = b.x - a.x;\n\tdouble deltay = b.y - a.y;\n\tif(max(-deltax, deltax) < eps) return (((deltax < 0) ? (-1) : 1) * deltay < 0) ? (-dinf) : (dinf);\n\n\treturn deltay / deltax; \n}\n\nstruct convex_hull {\n\tvector<point> st;\n\tconvex_hull() {st.clear();}\n\tvoid compute_hull(vector<point> vec) {\n\t\tsort(vec.begin(), vec.end(), cmp);\n\t\n\t\tfor(int i = 0; i < (int)vec.size(); i++) {\n\t\t\twhile(st.size() >= 2 && slope(st[st.size() - 2], vec[i]) >= slope(st[st.size() - 2], st[st.size() - 1])) \n\t\t\t\tst.pop_back();\n\t\t\tst.push_back(vec[i]);\n\t\t}\n\t\t\n\t\tst.pop_back();\n\t\tint k = st.size();\n\t\n\t\tfor(int i = vec.size() - 1; i >= 0; i--) {\n\t\t\twhile(st.size() - k >= 2 && slope(vec[i], st[st.size() - 2]) >= slope(st[st.size() - 1], st[st.size() - 2]))\n\t\t\t\tst.pop_back();\n\t\t\tst.push_back(vec[i]);\n\t\t}\n\n\t\tst.pop_back();\n\t}\n};\n\nint n;\nvector<point> a;\n\nvoid read()\n{\n\tcin >> n;\n\n\tfor(int i = 0; i < n; i++)\n\t{\n\t\tdouble x, y;\n\t\tcin >> x >> y;\n\t\ta.push_back(point(x, y));\n\t}\n}\n\nconvex_hull hull;\n\nvoid solve()\n{\n\thull.compute_hull(a);\n}\t\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/geometry/dynamic_upper_hull.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define SZ(x) ((int)x.size())\n#define ALL(V) V.begin(), V.end()\n#define L_B lower_bound\n#define U_B upper_bound\n#define pb push_back\n\nusing namespace std;\ntemplate<class T, class T1> int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; }\ntemplate<class T, class T1> int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; }\nconst int MAXN = (int)5e4 + 42;\n\nstruct PT\n{\n\tint x, y;\n\tPT() { x = y = 0; }\n\tPT(int _x, int _y) { x = _x; y = _y; }\n\n\tint64_t operator&(const PT &other) { return x * 1ll * other.y - y * 1ll * other.x; }\n\tPT operator+(const PT &other) const { return PT(x + other.x, y + other.y); }\n\tPT operator-(const PT &other) const { return PT(x - other.x, y - other.y); }\n};\n\nrandom_device rd;\nmt19937 mt(rd());\n\nint64_t eval(PT L, PT R) { return (L.y + R.y) * 1ll * (R.x - L.x); }\n\nstruct node\n{\n\tPT pnt;\n\tint prior, sz;\n\tint64_t answer;\n\n\tnode *l, *r, *leftmost, *rightmost, *prv;\n\tnode() { sz = 0; answer = prior = 0; leftmost = rightmost = prv = l = r = nullptr; pnt = PT(); }\n\tnode(PT a) {leftmost = rightmost = this; sz = 1; answer = 0; pnt = a; prior = mt(); prv = l = r = nullptr; }\n};\n\nusing pnode = node*;\n\ninline int size(pnode &t) { return t ? t->sz : 0; }\n\nvoid pull(pnode &t)\n{\n\tif(!t) return;\n\n\tt->answer = 0;\n\tt->sz = size(t->l) + size(t->r) + 1;\n\tt->leftmost = t->rightmost = t;\n\tt->prv = nullptr;\n\n\tif(t->l)\n\t{\n\t\tt->answer += t->l->answer;\n\t\tt->answer += eval(t->l->rightmost->pnt, t->pnt);\n\t\tt->prv = t->l->rightmost;\n\t\tt->leftmost = t->l->leftmost;\n\t}\n\n\tif(t->r)\n\t{\n\t\tt->answer += t->r->answer;\n\t\tt->answer += eval(t->pnt, t->r->leftmost->pnt);\n\t\tt->r->leftmost->prv = t;\n\t\tt->rightmost = t->r->rightmost;\n\t}\n}\n\nvoid merge(pnode &t, pnode l, pnode r)\n{\n\tif(!l) { t = r; return; }\n\tif(!r) { t = l; return; }\n\n\tif(l->prior > r->prior)\n\t\tmerge(l->r, l->r, r), t = l;\n\telse\n\t\tmerge(r->l, l, r->l), t = r;\n\n\tpull(t);\n}\n\nvoid split_x(pnode t, pnode &l, pnode &r, int k)\n{\n\tif(!t) { l = r = nullptr; return; }\n\n\tif(t->pnt.x <= k)\n\t\tsplit_x(t->r, t->r, r, k), l = t;\n\telse\n\t\tsplit_x(t->l, l, t->l, k), r = t;\n\n\tpull(t);\n}\n\nvoid split_sz(pnode t, pnode &l, pnode &r, int k, int add = 0)\n{\n\tif(!t) { l = r = nullptr; return; }\n\n\tint idx = size(t->l) + add;\n\tif(idx <= k)\n\t\tsplit_sz(t->r, t->r, r, k, idx + 1), l = t;\n\telse\n\t\tsplit_sz(t->l, l, t->l, k, add), r = t;\n\n\tpull(t);\n}\n\nint q, T;\nint tin[MAXN], tout[MAXN], n = 0;\nPT p[MAXN];\n\nvoid read()\n{\n\tcin >> q >> T;\n\tfor(int i = 0; i < q; i++)\n\t{\n\t\tchar type;\n\t\tcin >> type;\n\n\t\tif(type == '+')\n\t\t{\n\t\t\ttin[n++] = i;\n\t\t\ttout[n - 1] = q - 1;\n\n\t\t\tint _p, _t;\n\t\t\tcin >> _p >> _t;\n\t\t\tp[n - 1] = PT(_t, _p);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tint idx = 0;\n\t\t\tcin >> idx;\n\t\t\ttout[idx] = i - 1;\n\t\t}\n\t}\n}\n\npnode root;\nvector<int> li[4 * MAXN];\nint64_t answer[MAXN];\n\nvoid add(int ql, int qr, int i, int l, int r, int idx)\n{\n\tif(r < ql || qr < l)\n\t\treturn;\n\n\tif(ql <= l && r <= qr)\n\t{\n\t\tli[idx].pb(i);\n\t\treturn;\n\t}\n\n\tint mid = (l + r) >> 1;\n\tadd(ql, qr, i, l, mid, 2 * idx + 1);\n\tadd(ql, qr, i, mid + 1, r, 2 * idx + 2);\n}\n\nint64_t cww(const PT &a, const PT &b, const PT &c) { return (b - a) & (c - a); }\n\nint find_pref(pnode t, PT R)\n{\n\tif(!t) return 0;\n\tif(!t->prv || cww(t->prv->pnt, t->pnt, R) < 0)\n\t\treturn max(t->pnt.x, find_pref(t->r, R));\n\telse\n\t\treturn find_pref(t->l, R);\n}\n\nint find_suff(pnode t, PT L)\n{\n\tif(!t) return 0;\n\tif(t->prv == nullptr)\n\t\treturn find_suff(t->r, L);\n\telse \n\t{\n\t\tif(cww(L, t->prv->pnt, t->pnt) >= 0)\n\t\t\treturn max(t->prv->pnt.x, find_suff(t->r, L));\n\t\telse\n\t\t\treturn find_suff(t->l, L);\n\t}\n}\n\n\npair<bool, pnode> add(pnode &t, PT pnt)\n{\n\tpnode l, r, nw = new node(pnt);\n\tsplit_x(t, l, r, pnt.x);\n\n\tif(cww(l->rightmost->pnt, pnt, r->leftmost->pnt) >= 0)\n\t{\n\t\tmerge(t, l, r);\n\t\treturn {false, nullptr};\n\t}\n\n\tint good_pref = find_pref(l, pnt), bad_pref = find_suff(r, pnt);\n\tpnode rem_l, rem_r;\n\n\tsplit_x(l, l, rem_l, good_pref);\n\tsplit_x(r, rem_r, r, bad_pref);\n\n\t//cout << \"Adding \" << pnt.x << \" \" << pnt.y << \" -> \" << good_pref << \" \" << bad_pref << endl << flush;\n\t//cout << \"Sizes: \" << size(l) << \" \" << size(r) << endl << flush;\n\n\tassert(l != nullptr);\n\tassert(r != nullptr);\n\n\tpnode ret;\n\tmerge(t, l, nw);\n\tmerge(t, t, r);\n\tmerge(ret, rem_l, rem_r);\n\n\treturn {true, ret};\n}\n\nvoid solve(int l, int r, int idx)\n{\n\tstack<pair<int, pnode> > ST;\n\tfor(int i: li[idx])\n\t{\n\t\tpair<bool, pnode> q = add(root, p[i]);\n\t\tif(q.first == true) ST.push({p[i].x, q.second});\n\t}\n\n\tif(l == r)\n\t\tanswer[l] = root->answer;\n\telse\n\t{\n\t\tint mid = (l + r) >> 1;\n\t\tsolve(l, mid, 2 * idx + 1);\n\t\tsolve(mid + 1, r, 2 * idx + 2);\n\t}\n\n\twhile(!ST.empty())\n\t{\n\t\tauto mid = ST.top();\n\t\tST.pop();\n\n\t\tpnode L, R, dummy;\n\t\tsplit_x(root, L, R, mid.first);\n\t\tsplit_x(L, L, dummy, mid.first - 1);\n\n\t\tmerge(root, L, mid.second);\n\t\tmerge(root, root, R);\n\t}\n}\n\nvoid solve()\n{\n\tfor(int i = 0; i < n; i++) add(tin[i], tout[i], i, 0, q - 1, 0);\n\n\troot = nullptr;\n\tmerge(root, root, new node(PT(0, 0)));\n\tmerge(root, root, new node(PT(T, 0)));\n\tsolve(0, q - 1, 0);\n\n\tfor(int i = 0; i < q; i++)\n\t\tcout << answer[i] << endl;\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/geometry/kd-tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (int)1e5 + 42 + 17;\nconst int MAXD = 5;\n\ninline int64_t sq(int x) { return x * 1ll * x; }\n\nstruct point\n{\n\tint c[MAXD];\n\tpoint() { }\n};\n\nstruct cmp\n{\n\tint current_d;\n\tcmp() { current_d = 0; }\n\tcmp(int d) { current_d = d; }\n\tbool operator() (const point& a, const point& b)  { return a.c[current_d] < b.c[current_d]; }\n}; \n\nint64_t sq_dist(point a, point b, int d)\n{\n\tint64_t answer = 0;\n\tfor(int i = 0; i < d; i++)\n\t\tanswer += sq(a.c[i] - b.c[i]);\n\n\treturn answer;\n}\n\nstruct kd_tree\n{\n\tstruct node\n\t{\n\t\tpoint p;\n\t\tint L, R, axis;\n\t\tnode() { L = -1; R = -1; }\n\t\tnode(point _p) { L = -1; R = -1; p = _p; }\n\t};\n\n\tint psz = 0, D, root;\n\tnode tr[MAXN << 2];\n\n\tkd_tree() { D = 0; psz = 0; }\t\n\tkd_tree(int d) { D = d; psz = 0; }\n\n\tint new_node() { return psz++; }\n\n\tint build(point *from, point *to, int axis)\n\t{\n\t\tif(to - from == 0) \n\t\t\treturn -1;\n\t\n\t\tpoint *mid = from + (to - from) / 2;\n\t\t\n\t\tnth_element(from, mid, to, cmp(axis));\n\t\n\t\tint c_node = new_node();\n\t\ttr[c_node] = node(*mid);\n\t\t\n\t\ttr[c_node].axis = axis;\n\n\t\ttr[c_node].L = build(from, mid, (axis + 1) % D);\n\t\ttr[c_node].R = build(mid + 1, to, (axis + 1) % D);\n\n\t\treturn c_node;\n\t}\n\n\tvoid init(point *from, point *to, int d) \n\t{ \n\t\tD = d;\n\t\trandom_shuffle(from, to);\n\t\troot = build(from, to, 0);  \n\t}\n\n\tvoid query(int idx, point q, int64_t &answer)\n\t{\n\t\tif(idx == -1) return;\n\t\tanswer = min(answer, sq_dist(q, tr[idx].p, D));\n\t\t\n\t\tif(tr[idx].p.c[tr[idx].axis] <= q.c[tr[idx].axis])\n\t\t{\n\t\t\tquery(tr[idx].R, q, answer); \n\t\t\tif(tr[idx].L != -1 && q.c[tr[idx].axis] - sqrt(answer) <= tr[idx].p.c[tr[idx].axis]) query(tr[idx].L, q, answer); \n\t\t}\t\t\n\t\telse\n\t\t{\n\t\t\tquery(tr[idx].L, q, answer); \n\t\t\tif(tr[idx].R != -1 && q.c[tr[idx].axis] + sqrt(answer) >= tr[idx].p.c[tr[idx].axis]) query(tr[idx].R, q, answer); \n\t\t}\n\t}\n\n\tdouble nearest_neigbhor(point q)\n\t{\n\t\tint64_t answer = (1ll << 62ll);\n\t\tquery(root, q, answer);\n\t\treturn sqrt(answer); \n\t}\n};\n\nint n, d;\npoint li[MAXN];\n\nvoid read()\n{\n\tcin >> n >> d;\n\tfor(int i = 0; i < n; i++)\n\t\tfor(int x = 0; x < d; x++)\n\t\t\tcin >> li[i].c[x];\n}\n\nkd_tree t;\n\nvoid solve()\n{\n\tt.init(li, li + n, d);\n\n\tint q;\n\tcin >> q;\n\tfor(int i = 0; i < q; i++)\n\t{\n\t\tpoint q;\n\t\tfor(int x = 0; x < d; x++)\n\t\t\tcin >> q.c[x];\n\n\t\tcout << setprecision(10) << fixed << t.nearest_neigbhor(q) << endl;\n\t}\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/geometry/rectangle_union.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n\nusing namespace std;\nconst int MAXN = (1 << 21);\nconst int bound = (int)1e6 + 42;\nconst int inf = (int)1e9 + 42;\n\nstruct edge\n{\n\tint x, y1, y2, val;\n\tedge() {x = -1; y1 = -1; y2 = -1; val = -1;}\n\tedge(int _x, int _y1, int _y2, int _val)\n\t{\n\t\tx = _x;\n\t\ty1 = _y1;\n\t\ty2 = _y2;\n\t\tval = _val;\n\t}\n};\n\nbool operator<(const edge &e1, const edge &e2)\n{\n\treturn e1.x < e2.x;\n}\n\nint n;\nvector<edge> e;\n\nvoid read()\n{\n\tcin >> n;\n\tfor(int i = 0; i < n; i++)\n\t{\n\t\tint mnx, mny, mxx, mxy;\n\t\tcin >> mnx >> mny >> mxx >> mxy;\n\n\t\tif(mxx < mnx) swap(mxx, mnx);\n\t\tif(mxy < mny) swap(mxy, mny);\n\t\tmnx--;\n\t\tmny--;\n\n\t\te.push_back(edge(mnx, mny, mxy, 1));\n\t\te.push_back(edge(mxx, mny, mxy, -1));\n\t}\t\n}\n\nint valy[MAXN];\nvector<int> comy;\nmap<int, int> id_y;\nint sz_y;\n\nvoid compress()\n{\n\tfor(int i = 0; i < e.size(); i++)\n\t{\n\t\tcomy.push_back(e[i].y1);\n\t\tcomy.push_back(e[i].y2);\n\t}\n\n\tsort(comy.begin(), comy.end());\n\tid_y[comy[0]] = 1;\n\n\tfor(int i = 1; i < comy.size(); i++)\n\t\tif(comy[i] != comy[i - 1])\n\t\t\tid_y[comy[i]] = id_y[comy[i - 1]] + 1ll;\n\n\tfor(int i = 0; i < comy.size(); i++)\n\t\tvaly[id_y[comy[i]]] = comy[i];\n\n\tfor(int i = 0; i < e.size(); i++)\n\t{\n\t\te[i].y1 = id_y[e[i].y1];\n\t\te[i].y2 = id_y[e[i].y2];\n\t}\n\n\tsz_y = id_y.size();\n}\n\nstruct segment_tree\n{\n\tstruct node\n\t{\n\t\tint lazy, ans;\n\t\tnode() {lazy = 0, ans = 0;}\n\t\tnode(int v) { ans = v; lazy = 0;}\n\t};\n\n\tnode tr[4 * MAXN];\n\n\tvoid update(int qL, int qR, int val, int l, int r, int idx)\n\t{\n\t\tif(qL <= l && r <= qR)\n\t\t{\n\t\t\ttr[idx].lazy += val;\n\t\t\tif(tr[idx].lazy == 0) tr[idx].ans = tr[2 * idx + 1].ans + tr[2 * idx + 2].ans; \n\t\t\telse tr[idx].ans = valy[r] - valy[l];\n\t\t\treturn;\n\t\t}\n\n\t\tif(qL > r || qR < l)\n\t\t\treturn;\n\t\n\t\tif(l + 1 >= r)\n\t\t\treturn;\n\n\t\tint mid = (l + r) >> 1;\n\t\tupdate(qL, qR, val, l, mid, 2 * idx + 1);\n\t\tupdate(qL, qR, val, mid, r, 2 * idx + 2);\n\n\t\tif(tr[idx].lazy == 0) tr[idx].ans = tr[2 * idx + 1].ans + tr[2 * idx + 2].ans;\n\t\telse tr[idx].ans = valy[r] - valy[l];\n\t}\n};\n\nsegment_tree t;\n\ninline int mabs(int x) { return x < 0 ? -x : x; }\n\nint rectangle_union()\n{\n\tcompress();\n\tsort(e.begin(), e.end());\n\n\tint ans = 0, last = -inf;\n\tfor(int i = 0; i < e.size(); i++)\n\t{\n\t\tans += mabs(e[i].x - last) * (long long)t.tr[0].ans;\n\t\tt.update(e[i].y1, e[i].y2, e[i].val, 1, sz_y, 0);\n\t\tlast = e[i].x;\n\t}\n\n\treturn ans;\n}\n\nvoid solve()\n{\n\tcout << rectangle_union() << endl;\t\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/graph/dsu_bipartite.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nint n, m;\npair<int, int> e[MAXN];\n\nvoid read() {\n\tcin >> n >> m;\n\tfor(int i = 0; i < m; i++) cin >> e[i].first >> e[i].second;\n}\n\nint ds_sz[MAXN], col[MAXN], par[MAXN];\nvector<int> li[MAXN];\n\nint root(int u) {\n\tif(u == par[u]) return u;\n\treturn (par[u] = root(par[u]));\n}\n\nvoid unite(int u, int v) {\n\tif(root(u) == root(v)) {\n\t\tif(col[u] == col[v]) {\n\t\t\tcout << \"NO\" << endl;\n\t\t\texit(0);\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif(li[root(u)].size() > li[root(v)].size()) swap(u, v);\n\n\tif(col[u] == col[v])\n\t\tfor(int ver: li[root(u)]) col[ver] ^= 1;\n\n\tfor(int ver: li[root(u)]) li[root(v)].push_back(ver);\n\n\tpar[root(u)] = root(v);\n}\n\nvoid solve() {\n\tfor(int i = 1; i <= n; i++)\n\t\tds_sz[i] = 1, col[i] = 1, li[i].push_back(i), par[i] = i;\n\n\tfor(int i = 0; i < m; i++) unite(e[i].first, e[i].second);\n\n\tcout << \"YES\" << endl;\n}\n\nint main() {\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/graph/eulerian_path.cpp",
    "content": "#include <bits/stdc++.h>\n\nusing namespace std;\n\ntemplate<class T, class T1>\nint chkmin(T &x, const T1 &y) {\n    return x > y ? x = y, 1 : 0;\n}\n\ntemplate<class T, class T1>\nint chkmax(T &x, const T1 &y) {\n    return x < y ? x = y, 1 : 0;\n}\n\ntemplate<typename T1, typename T2>\nostream &operator<<(ostream &out, const pair<T1, T2> &x) {\n    return out << x.first << ' ' << x.second;\n}\n\ntemplate<typename T1, typename T2>\nistream &operator>>(istream &in, pair<T1, T2> &x) {\n    return in >> x.first >> x.second;\n}\n\ntemplate<typename T>\nistream &operator>>(istream &in, vector<T> &a) {\n    for(auto &x: a) {\n        in >> x;\n    }\n    return in;\n};\n\ntemplate<typename T>\nostream &operator<<(ostream &out, vector<T> &a) {\n    for(auto &x: a) {\n        out << x << ' ';\n    }\n    return out;\n};\n\n/*\n    https://codesprintla24.kattis.com/contests/codesprintla24open/problems/catbusplan\n\n    Problem Statement:\n    Split a graph into k edge-disjoint paths.\n\n    Note that the Eulerian path algorithm works only when there are at most 2 odd \n    degree vertices, as otherwise, when starting the DFS from a degree of odd degree,\n    you might disconnect the graph (and the splicing of the cycles on the path doesn't \n    work). To fix this, we add fake edges between all but one pair of vertices of odd \n    degree, and then start the DFS from one of the 2 odd vertices that are left.\n*/\n\nint n, m, k;\nvector<vector<pair<int, int>>> adj;\nvector<pair<int, int>> edges;\n\nvoid read() {\n    cin >> n >> m >> k;\n    adj.assign(n, {});\n    edges.resize(m);\n    for(int i = 0; i < m; i++) {\n        int u, v;\n        cin >> u >> v;\n        u--, v--;\n        adj[u].push_back({v, i * 2});\n        adj[v].push_back({u, i * 2 + 1});\n        edges[i] = {u, v};\n    }\n}\n\nvector<int> answer;\nvector<bool> used;\nvector<int> po;\nvector<int> deg;\n\nvoid dfs(int u) {\n    for(; po[u] < (int)adj[u].size();) {\n        int idx = po[u]++;\n        if(!used[adj[u][idx].second >> 1]) {\n            used[adj[u][idx].second >> 1] = true;\n            dfs(adj[u][idx].first);\n            answer.push_back(adj[u][idx].second);\n        }\n    }\n}\n\npair<int, int> get_edge(int edge_i) {\n    if(edge_i & 1) {\n        return edges[edge_i >> 1];\n    } else {\n        return {edges[edge_i >> 1].second, edges[edge_i >> 1].first};\n    }\n}\n\nvoid dfs_visit_nodes(int u, vector<bool> &visited, vector<int> &nodes) {\n    nodes.push_back(u);\n    visited[u] = true;\n    for(auto [v, edge_i]: adj[u]) {\n        if(!visited[v]) {\n            dfs_visit_nodes(v, visited, nodes);\n        }\n    }\n}\n\nvoid solve() {\n    if(k > m) {\n        cout << \"Impossible\\n\";\n        return;\n    }\n\n    used.assign(m, false);\n    po.assign(n, 0);\n    deg.assign(n, 0);\n\n    vector<bool> used_vers(n, false);\n\n    for(int i = 0; i < n; i++) {\n        deg[i] = adj[i].size();\n    }\n\n    int broken = m;\n\n    vector<vector<int>> pre_paths;\n    for(int u = 0; u < n; u++) {\n        if(!used_vers[u]) {\n            vector<int> nodes_here;\n            dfs_visit_nodes(u, used_vers, nodes_here);\n\n            vector<pair<int, int>> broken_edges_here;\n            int last_odd = -1;\n            for(int i: nodes_here) {\n                if(deg[i] % 2 == 1) {\n                    if(last_odd != -1) {\n                        broken_edges_here.push_back({last_odd, i});\n                        last_odd = -1;\n                    } else {\n                        last_odd = i;\n                    }\n                }\n            }\n\n            while((int)broken_edges_here.size() > 1) {\n                auto [i, j] = broken_edges_here.back();\n                adj[i].push_back({j, 2 * broken});\n                adj[j].push_back({i, 2 * broken + 1});\n                broken++;\n                used.push_back(false);\n                edges.push_back({i, j});\n                deg[i]++;\n                deg[j]++;\n                broken_edges_here.pop_back();\n            }\n\n            answer.clear();\n            if(!broken_edges_here.empty()) {\n                dfs(broken_edges_here[0].first);\n            } else {\n                dfs(u);\n            }\n\n            pre_paths.push_back(answer);\n        }\n    }\n\n    vector<vector<int>> paths;\n    for(auto path: pre_paths) {\n        vector<int> new_path;\n        for(int x: path) {\n            if(x >= 2 * m) {\n                if(!new_path.empty()) {\n                    paths.push_back(new_path);\n                }\n                new_path.clear();\n            } else {\n                new_path.push_back(x);\n            }\n        }\n\n        if(!new_path.empty()) {\n            paths.push_back(new_path);\n        }\n    }\n\n    if((int)paths.size() > k) {\n        cout << \"Impossible\\n\";\n        return;\n    }\n\n    int need = k - (int)paths.size();\n    for(int i = 0; i < (int)paths.size(); i++) {\n        while((int)paths[i].size() > 1 && need > 0) {\n            paths.push_back({paths[i].back()});\n            paths[i].pop_back();\n            need--;\n        }\n    }\n\n    assert(need == 0);\n    cout << \"Possible\\n\";\n    for(auto &path: paths) {\n        cout << get_edge(path[0]).first + 1 << ' ';\n        for(auto edge_i: path) {\n            cout << get_edge(edge_i).second + 1 << ' ';\n        }\n\n        cout << endl;\n    }\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int T = 1;\n    // cin >> T;\n    for(int test = 1; test <= T; test++) {\n        read();\n        // cout << \"Case #\" << test << \": \";\n        solve();\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/graph/max_anticlique.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (52);\n\nint G[MAXN][MAXN], n;\nint mn_deg, comp_size;\nbitset<MAXN> st;\nvector<int> adj[MAXN];\nbool visited[MAXN];\n\nint get_deg(int u) {\n    int res = 0;\n    for(int v = 0; v < n; v++)\n        if(st[v]) res += G[u][v];\n\n    return res;\n}\n\nvoid dfs(int u) {\n    visited[u] = true;\n    mn_deg = min(mn_deg, (int)adj[u].size());\n    comp_size++;\n    for(int v: adj[u])\n        if(!visited[v]) dfs(v);\n}\n\nint brute() {\n    for(int u = 0; u < n; u++)\n        if(st[u]) visited[u] = false, adj[u].clear();\n    for(int u = 0; u < n; u++)\n        if(st[u])\n            for(int v = 0; v < n; v++)\n                if(G[u][v] && st[v]) adj[u].push_back(v);\n\n    int res = 0;\n    for(int u = 0; u < n; u++)\n        if(st[u] && !visited[u]) {\n            mn_deg = MAXN;\n            comp_size = 0;\n            dfs(u);\n\n            if(mn_deg <= 1)\n                res += ((comp_size + 1) / 2);\n            else\n                res += (comp_size / 2);\n        }\n\n    return res;\n}\n\nint rec() {\n    if(!st.count()) return 0;\n\n    int d = -1;\n    for(int v = 0; v < n; v++)\n        if(st[v] && (d == -1 || get_deg(v) > get_deg(d))) d = v;\n\n    if(get_deg(d) <= 2) return brute();\n\n    int ret = 0;\n    bitset<MAXN> prv = st;\n\n    st[d] = 0;\n    ret = max(ret, rec());\n\n    st = prv;\n    st[d] = 0;\n    for(int u = 0; u < n; u++)\n        if(G[u][d]) st[u] = 0;\n\n    ret = max(ret, 1 + rec());\n\n    st = prv;\n    return ret;\n}\n\n/// O(1.38 ^ n) worst case\nint max_anticlique() {\n    for(int i = 0; i < n; i++) st[i] = 1;\n    return rec();\n}\n\nvoid read() {}\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/graph/maximum_closure.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\ntemplate<class T, class T2> inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; }\ntemplate<class T, class T2> inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; }\nconst int MAXN = (1 << 20);\n\ntemplate<class FlowT>\nstruct max_flow\n{\n    const static FlowT finf = 1e18 + 42 + 17;\n    const static FlowT feps = 0;\n\n    struct edge\n    {\n        FlowT flow, cap;\n        int idx, rev, to;\n        edge() { flow = 0; cap = 0; rev = 0; idx = 0; to = 0; }\n        edge(int _to, int _rev, FlowT _flow, FlowT _cap, int _idx)\n        {\n            to = _to; rev = _rev;\n            flow = _flow; cap = _cap;\n            idx = _idx;\n        }\n    };\n\n    vector<edge> G[MAXN];\n    int n, dist[MAXN], po[MAXN];\n\n    bool bfs(int s, int t)\n    {\n        dist[s] = -1, po[s] = 0;\n        dist[t] = -1, po[t] = 0;\n        for(int v = 0; v <= n; v++)\n            dist[v] = -1, po[v] = 0;\n\n        queue<int> Q;\n        Q.push(s);\n        dist[s] = 0;\n\n        while(!Q.empty())\n        {\n            int u = Q.front();\n            Q.pop();\n\n            for(edge e: G[u])\n                if(dist[e.to] == -1 && e.flow < e.cap)\n                {\n                    dist[e.to] = dist[u] + 1;\n                    Q.push(e.to);\n                }\n        }\n\n        return dist[t] != -1;\n    }\n\n    FlowT dfs(int u, int t, FlowT fl = finf)\n    {\n        if(u == t)\n            return fl;\n\n        for(; po[u] < G[u].size(); po[u]++)\n        {\n            auto &e = G[u][po[u]];\n            if(dist[e.to] == dist[u] + 1 && e.flow < e.cap)\n            {\n                FlowT f = dfs(e.to, t, min(fl, e.cap - e.flow));\n\n                e.flow += f;\n                G[e.to][e.rev].flow -= f;\n\n                if(f > 0)\n                    return f;\n            }\n        }\n\n        return 0;\n    }\n\n    void init(int _n) { n = _n; for(int i = 0; i <= n; i++) G[i].clear(); }\n\n    void add_edge(int u, int v, FlowT w, int idx = -1)\n    {\n        G[u].push_back(edge(v, G[v].size(), 0, w, idx));\n        G[v].push_back(edge(u, G[u].size() - 1, 0, 0, -1));\n    }\n\n    FlowT flow(int s, int t)\n    {\n        if(s == t) return finf;\n\n        FlowT ret = 0, to_add;\n        while(bfs(s, t))\n            while((to_add = dfs(s, t)))\n                ret += to_add;\n\n        return ret;\n    }\n};\n\ntemplate<class T>\nstruct maximum_closure\n{\n\tint n;\n\tT w[MAXN];\n\tmax_flow<T> mf;\n\tvector<int> adj[MAXN];\n\n\tvoid init(int _n)\n\t{\n\t\tn = _n;\n\t\tfor(int i = 1; i <= n; i++)\n\t\t\tw[i] = 0, adj[i].clear();\n\t}\n\n\tvoid add_clause(int i, int j) { adj[i].push_back(j); }\n\n\tint dfs_time, cnt_comp, comp[MAXN], disc[MAXN], low[MAXN];\n\tbool in_stack[MAXN];\n\tstack<int> st;\n\n\tvoid dfs_tarjan(int u)\n\t{\n\t\tdisc[u] = low[u] = ++dfs_time;\n\t\tin_stack[u] = 1;\n\t\tst.push(u);\n\n\t\tfor(int v: adj[u])\n\t\t\tif(disc[v] == -1)\n\t\t\t{\n\t\t\t\tdfs_tarjan(v);\n\t\t\t\tchkmin(low[u], low[v]);\n\t\t\t}\n\t\t\telse if(in_stack[v])\n\t\t\t\tchkmin(low[u], disc[v]);\n\t\n\t\tif(low[u] == disc[u])\n\t\t{\n\t\t\tcnt_comp++;\n\t\t\twhile(st.top() != u)\n\t\t\t{\n\t\t\t\tin_stack[st.top()] = 0;\n\t\t\t\tcomp[st.top()] = cnt_comp;\n\t\t\t\tst.pop();\n\t\t\t}\n\n\t\t\tcomp[u] = cnt_comp;\n\t\t\tin_stack[u] = 0;\n\t\t\tst.pop();\n\t\t}\n\t}\n\n\tT solve()\n\t{\n\t\tfor(int i = 1; i <= n; i++)\t\t\n\t\t\tdisc[i] = -1;\n\n\t\tdfs_time = 0, cnt_comp = 0;\n\t\tfor(int i = 1; i <= n; i++)\n\t\t\tif(disc[i] == -1)\n\t\t\t\tdfs_tarjan(i);\n\n\t\tint s = cnt_comp + 1, t = cnt_comp + 2;\n\t\tmf.init(cnt_comp + 3);\n\n\t\tvector<T> new_w;\n\t\tnew_w.assign(cnt_comp + 1, 0);\n\t\tfor(int i = 1; i <= n; i++)\n\t\t\tnew_w[comp[i]] += w[i];\n\n\t\tfor(int i = 1; i <= n; i++)\n\t\t\tfor(int j: adj[i])\n\t\t\t\tmf.add_edge(comp[i], comp[j], max_flow<T>::finf);\n\n\t\tT sum = 0;\n\t\tfor(int i = 1; i <= cnt_comp; i++)\n\t\t{\n\t\t\tif(new_w[i] < 0) mf.add_edge(s, i, -new_w[i]);\n\t\t\telse mf.add_edge(i, t, new_w[i]), sum += new_w[i]; \n\t\t}\n\n\t\treturn sum - mf.flow(s, t);\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/graph/mincost_maxflow.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 10);\nconst int inf = (int)1e9 + 42;\n\nint read_int();\n\nstruct edge {\n    int to, rev, flow, cap, cost;\n    edge() {\n        to = 0;\n        rev = 0;\n        flow = 0;\n        cap = 0;\n        cost = 0;\n    }\n    edge(int _to, int _rev, int _flow, int _cap, int _cost) {\n        to = _to;\n        rev = _rev;\n        flow = _flow;\n        cap = _cap;\n        cost = _cost;\n    }\n};\n\nint cnt_nodes = 0, s = MAXN - 1, t = MAXN - 2;\nvector<edge> G[MAXN];\n\nvoid add_edge(int u, int v, int w, int cost) {\n    edge t = edge(v, G[v].size(), 0, w, cost);\n    edge r = edge(u, G[u].size(), 0, 0, -cost);\n    G[u].push_back(t);\n    G[v].push_back(r);\n}\n\ndeque<int> Q;\nbool is_inside[MAXN];\nint dist[MAXN], par_idx[MAXN], par[MAXN];\n\nbool spfa() {\n    for(int i = 0; i <= cnt_nodes; i++) {\n        dist[i] = inf;\n    }\n    dist[t] = inf;\n\n    Q.clear();\n    dist[s] = 0;\n    is_inside[s] = true;\n    Q.push_back(s);\n\n    while(!Q.empty()) {\n        int u = Q.front();\n        is_inside[u] = false;\n        Q.pop_front();\n\n        for(int i = 0; i < (int)G[u].size(); i++) {\n            if(G[u][i].cap > G[u][i].flow &&\n               dist[u] + G[u][i].cost < dist[G[u][i].to]) {\n                dist[G[u][i].to] = dist[u] + G[u][i].cost;\n                par_idx[G[u][i].to] = i;\n                par[G[u][i].to] = u;\n\n                if(is_inside[G[u][i].to]) {\n                    continue;\n                }\n                if(!Q.empty() && dist[G[u][i].to] > dist[Q.front()]) {\n                    Q.push_back(G[u][i].to);\n                } else {\n                    Q.push_front(G[u][i].to);\n                }\n\n                is_inside[G[u][i].to] = true;\n            }\n        }\n    }\n\n    return dist[t] != inf;\n}\n\npair<int, int> min_cost_flow(int flow) {\n    int f = 0, ret = 0;\n    while(f <= flow && spfa()) {\n        int mn_flow = flow - f, u = t;\n        while(u != s) {\n            mn_flow =\n                min(mn_flow,\n                    G[par[u]][par_idx[u]].cap - G[par[u]][par_idx[u]].flow);\n            u = par[u];\n        }\n\n        u = t;\n        while(u != s) {\n            G[par[u]][par_idx[u]].flow += mn_flow;\n            G[u][G[par[u]][par_idx[u]].rev].flow -= mn_flow;\n            ret += G[par[u]][par_idx[u]].cost * mn_flow;\n            u = par[u];\n        }\n\n        f += mn_flow;\n    }\n\n    return make_pair(f, ret);\n}\n\nvoid read() {}\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n\nconst int maxl = 100000;\nchar buff[maxl];\nint ret_int, pos_buff = 0;\n\nvoid next_char() {\n    if(++pos_buff == maxl) {\n        fread(buff, 1, maxl, stdin), pos_buff = 0;\n    }\n}\n\nint read_int() {\n    ret_int = 0;\n    for(; buff[pos_buff] < '0' || buff[pos_buff] > '9'; next_char())\n        ;\n    for(; buff[pos_buff] >= '0' && buff[pos_buff] <= '9'; next_char()) {\n        ret_int = ret_int * 10 + buff[pos_buff] - '0';\n    }\n    return ret_int;\n}\n"
  },
  {
    "path": "old_impl/graph/persistent_dsu.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct persistent_dsu\n{\n\tstruct state\n\t{\n\t\tint u, v, rnku, rnkv;\n\t\tstate() {u = -1; v = -1; rnkv = -1; rnku = -1;}\n\t\tstate(int _u, int _rnku, int _v, int _rnkv)\n\t\t{\n\t\t\tu = _u;\n\t\t\trnku = _rnku;\n\t\t\tv = _v;\n\t\t\trnkv = _rnkv;\n\t\t}\n\t};\n\n\tstack<state> st;\n\tint par[MAXN], depth[MAXN];\n\tpersistent_dsu() {memset(par, -1, sizeof(par)); memset(depth, 0, sizeof(depth));}\n\n\tint root(int x)\n\t{\n\t\tif(x == par[x]) return x;\n\t\treturn root(par[x]);\n\t}\n\n\tvoid init(int n)\n\t{\n\t\tfor(int i = 0; i <= n; i++)\n\t\t{\n\t\t\tpar[i] = i;\n\t\t\tdepth[i] = 1;\n\t\t}\n\t}\n\n\tbool connected(int x, int y)\n\t{\n\t\treturn root(x) == root(y);\n\t}\n\n\tvoid unite(int x, int y)\n\t{\n\t\tint rx = root(x), ry = root(y);\n\t\tst.push(state(rx, depth[rx], ry, depth[ry]));\n\t\t\n\t\tif(depth[rx] < depth[ry])\n\t\t\tpar[rx] = ry;\n\t\telse if(depth[ry] < depth[rx])\n\t\t\tpar[ry] = rx;\n\t\telse\n\t\t{\n\t\t\tpar[rx] = ry;\n\t\t\tdepth[rx]++;\n\t\t}\n\t}\n\n\tvoid backtrack(int c)\n\t{\n\t\twhile(!st.empty() && c)\n\t\t{\n\t\t\tpar[st.top().u] = st.top().u;\n\t\t\tpar[st.top().v] = st.top().v;\n\t\t\tdepth[st.top().u] = st.top().rnku;\n\t\t\tdepth[st.top().v] = st.top().rnkv;\n\t\t\tst.pop();\n\t\t\tc--;\n\t\t}\n\t}\n};\n\nvoid read()\n{\n\n}\n\npersistent_dsu d;\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/graph/scc_tarjan.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nint n, m;\nvector<int> G[MAXN];\n\nvoid read()\n{\n\tcin >> n >> m;\n\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\tint u, v;\n\t\tcin >> u >> v;\n\n\t\tG[u].push_back(v);\n\t}\n}\n\nstack<int> st;\nvector<vector<int>> scc; \nint low[MAXN], disc[MAXN], comp[MAXN];\nint dfs_time;\nbool in_stack[MAXN];\n\nvoid dfs(int u)\n{\n\tlow[u] = dfs_time;\n\tdisc[u] = dfs_time;\n\tdfs_time++;\n\n\tin_stack[u] = true;\n\tst.push(u);\n\t\n\tint sz = G[u].size(), v;\n\tfor(int i = 0; i < sz; i++)\n\t{\n\t\tv = G[u][i];\n\t\n\t\tif(disc[v] == -1)\n\t\t{\n\t\t\tdfs(v);\n\t\t\tlow[u] = min(low[u], low[v]);\n\t\t}\n\t\telse if(in_stack[v] == true)\n\t\t\tlow[u] = min(low[u], disc[v]);\n\t}\n\n\tif(low[u] == disc[u])\n\t{\n\t\tscc.push_back(vector<int>());\n\t\twhile(st.top() != u)\n\t\t{\n\t\t\tscc[scc.size() - 1].push_back(st.top());\n\t\t\tin_stack[st.top()] = false;\n\t\t\tst.pop();\n\t\t}\n\n\t\tscc[scc.size() - 1].push_back(u);\n\t\tin_stack[u] = false;\n\t\tst.pop();\n\t}\n}\n\nvoid tarjan()\n{\n\tmemset(comp, -1, sizeof(comp));\n\tmemset(disc, -1, sizeof(disc));\n\tmemset(low, -1, sizeof(low));\n\tmemset(in_stack, 0, sizeof(in_stack));\n\tdfs_time = 0;\n\n\twhile(!st.empty())\n\t\tst.pop();\n\n\tfor(int i = 1; i <= n; i++)\n\t\tif(disc[i] == -1)\n\t\t\tdfs(i);\n\n\tint sz = scc.size();\n\tfor(int i = 0; i < sz; i++)\n\t\tfor(int j = 0; j < (int)scc[i].size(); j++)\n\t\t\tcomp[scc[i][j]] = i;\n}\n\nvoid solve()\n{\n\ttarjan();\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/graph/st_numbering.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n//#pragma GCC optimize (\"O3\")\n//#pragma GCC target (\"sse4\")\n\nusing namespace std;\ntemplate<class T, class T2> inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; }\ntemplate<class T, class T2> inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\n\nint n, m, s, t;\nvector<int> adj[MAXN];\n\nvoid read() {\n\tcin >> n >> m >> s >> t;\n\tfor(int i = 0; i < m; i++) {\n\t\tint u, v;\n\t\tcin >> u >> v;\n\t\tadj[u].push_back(v);\n\t\tadj[v].push_back(u);\n\t}\n}\n\nint low[MAXN], disc[MAXN], dfs_time = 0, par[MAXN], sign[MAXN];\nvector<int> preorder;\n\nbool tarjan_check(int u, int pr = -1) {\n\tlow[u] = disc[u] = ++dfs_time;\n\n\tint child_cnt = 0;\n\tfor(int v: adj[u])\n\t\tif(v != pr) {\n\t\t\tif(disc[v] == -1) {\n\t\t\t\tchild_cnt++;\n\t\t\t\tif(!tarjan_check(v, u)) return false;\n\t\t\t\tchkmin(low[u], low[v]);\n\t\t\t\tif(pr != -1 && low[v] >= disc[u]) return false;\n\t\t\t}\n\t\t\telse chkmin(low[u], disc[v]);\n\t\t}\n\n\tif(pr == -1 && child_cnt > 1) return false;\n\treturn true;\n}\n\nvoid tarjan(int u, int pr = -1) {\n\tlow[u] = disc[u] = ++dfs_time;\n\tfor(int v: adj[u])\n\t\tif(v != pr) {\n\t\t\tif(disc[v] == -1) {\n\t\t\t\tpreorder.push_back(v);\n\t\t\t\ttarjan(v, u);\n\t\t\t\tchkmin(low[u], low[v]);\n\t\t\t\tpar[v] = u;\n\t\t\t}\n\t\t\telse chkmin(low[u], disc[v]);\n\t\t}\n}\n\nlist<int> st_li;\nlist<int>::iterator it_ver[MAXN];\n\nvector<int> st_numbering() {\n\t/// additional edge\n\tadj[s].push_back(t);\n\tadj[t].push_back(s);\n\n\tdfs_time = 0;\n\tpreorder.clear();\n\tfor(int i = 1; i <= n; i++) disc[i] = low[i] = -1, sign[i] = 0;\n\n\tif(!tarjan_check(t))\n\t\treturn vector<int>(); /// no bipolar orientation\n\n\tfor(int i = 1; i <= n; i++)\n\t\tif(disc[i] == -1)\n\t\t\treturn vector<int>(); /// no bipolar orientation\n\n\tfor(int i = 1; i <= n; i++) disc[i] = low[i] = -1, sign[i] = 0;\n\n\tdfs_time = 0;\n\tpreorder.clear();\n\tdisc[s] = low[s] = ++dfs_time;\n\tsign[disc[s]] = -1;\n\ttarjan(t);\n\n\tst_li.clear();\n\tst_li.push_back(s);\n\tst_li.push_back(t);\n\n\tit_ver[disc[s]] = st_li.begin();\n\tit_ver[disc[t]] = next(st_li.begin());\n\n\tfor(int v: preorder) {\n\t\tif(sign[low[v]] == -1) it_ver[disc[v]] = st_li.insert(it_ver[disc[par[v]]], v);\n\t\telse it_ver[disc[v]] = st_li.insert(next(it_ver[disc[par[v]]]), v);\n\t\tsign[disc[par[v]]] = -sign[low[v]];\n\t}\n\n\tvector<int> ret(st_li.begin(), st_li.end());\n\treturn ret;\n}\n\nvoid solve() {\n\tvector<int> li = st_numbering();\n\tfor(int v: li) cout << v << \" \";\n\tcout << endl;\n}\n\nint main() {\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/math/combinatorics.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\nconst int mod = (int)1e9 + 7;\n\ntemplate<class T>\nT pw(T a, int pw) {\n    T ret(1);\n    while(pw) {\n        if(pw & 1) {\n            ret *= a;\n        }\n        a *= a;\n        pw >>= 1;\n    }\n\n    return ret;\n}\n\ntemplate<unsigned mod>\nclass modint_t {\n  private:\n    unsigned x;\n\n  public:\n    modint_t() { x = 0; }\n    modint_t(unsigned _x) { x = _x; }\n    operator unsigned() { return x; }\n\n    bool operator==(const modint_t& m) const { return x == m.x; }\n    bool operator!=(const modint_t& m) const { return x != m.x; }\n\n    modint_t operator+=(const modint_t& m) {\n        x = (x + m.x >= mod ? x + m.x - mod : x + m.x);\n        return *this;\n    }\n    modint_t operator-=(const modint_t& m) {\n        x = (x < m.x ? x - m.x + mod : x - m.x);\n        return *this;\n    }\n    modint_t operator*=(const modint_t& m) {\n        x = 1ULL * x * m.x % mod;\n        return *this;\n    }\n\n    modint_t operator+=(const int32_t m) {\n        x = (x + (m % mod) >= mod ? x + (m % mod) - mod : x + (m % mod));\n        return *this;\n    }\n    modint_t operator-=(const int32_t m) {\n        x = (x < (m % mod) ? x - (m % mod) + mod : x - (m % mod));\n        return *this;\n    }\n    modint_t operator*=(const int32_t m) {\n        x = 1ULL * x * (m % mod) % mod;\n        return *this;\n    }\n\n    modint_t operator+=(const int64_t m) {\n        x = (x + (m % mod) >= mod ? x + (m % mod) - mod : x + (m % mod));\n        return *this;\n    }\n    modint_t operator-=(const int64_t m) {\n        x = (x < (m % mod) ? x - (m % mod) + mod : x - (m % mod));\n        return *this;\n    }\n    modint_t operator*=(const int64_t m) {\n        x = 1ULL * x * (m % mod) % mod;\n        return *this;\n    }\n\n    modint_t operator+(const modint_t& m) const { return modint_t(*this) += m; }\n    modint_t operator-(const modint_t& m) const { return modint_t(*this) -= m; }\n    modint_t operator*(const modint_t& m) const { return modint_t(*this) *= m; }\n\n    modint_t operator+(const int32_t m) const { return modint_t(*this) += m; }\n    modint_t operator-(const int32_t m) const { return modint_t(*this) -= m; }\n    modint_t operator*(const int32_t m) const { return modint_t(*this) *= m; }\n\n    modint_t operator+(const int64_t m) const { return modint_t(*this) += m; }\n    modint_t operator-(const int64_t m) const { return modint_t(*this) -= m; }\n    modint_t operator*(const int64_t m) const { return modint_t(*this) *= m; }\n\n    modint_t inv() { return pw(modint_t(*this), mod - 2); }\n};\n\nusing mint = modint_t<mod>;\n\nvector<mint> fact, ifact, inv_prec;\n\nvoid precompute(int bound) {\n    fact.resize(bound + 1);\n    ifact.resize(bound + 1);\n    inv_prec.resize(bound + 1);\n\n    fact[0] = 1;\n    for(int i = 1; i <= bound; i++) {\n        fact[i] = fact[i - 1] * i;\n    }\n\n    ifact[bound] = fact[bound].inv();\n    for(int i = bound - 1; i >= 0; i--) {\n        ifact[i] = ifact[i + 1] * (i + 1);\n    }\n\n    for(int i = 1; i <= bound; i++) {\n        inv_prec[i] = fact[i - 1] * ifact[i];\n    }\n}\n\nmint C(int n, int k) {\n    if(n < k || n < 0 || k < 0) {\n        return 0;\n    }\n    return fact[n] * ifact[n - k] * ifact[k];\n}\n\nint main() {\n    precompute((int)1e6 + 42);\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/math/fft.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst double PI = acos(-1);\nconst int MAXN = (1 << 21);\n\nstruct complex_base\n{\n\tdouble x, y;\n\tcomplex_base(double _x = 0, double _y = 0) { x = _x; y = _y; }\n\tfriend complex_base operator-(const complex_base &a, const complex_base &b) { return complex_base(a.x - b.x, a.y - b.y); }\n\tfriend complex_base operator+(const complex_base &a, const complex_base &b) { return complex_base(a.x + b.x, a.y + b.y); }\n\tfriend 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); }\n\tfriend void operator/=(complex_base &a, const double &P) { a.x /= P; a.y /= P; }\n};\n\nint bit_rev[MAXN];\nint last_n_fft = -1, ilast_n_fft = -1;\ncomplex_base root[MAXN], iroot[MAXN];\n\nvoid fft(complex_base *a, int lg)\n{\n\tint n = (1 << lg);\n\tif(last_n_fft != n)\n\t{\n\t\tdouble ang = 2 * PI / n;\n\t\tfor(int i = 0; i < (n >> 1); i++)\n\t\t\troot[i] = complex_base(cos(ang * i), sin(ang * i));\n\n\t\tlast_n_fft = n;\n\t}\n\n\tfor(int i = 1; i < n; i++)\n\t{\n\t\tbit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));\n\t\tif(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]);\n\t}\n\n\tfor(int len = 2; len <= n; len <<= 1)\n\t{\n\t\tint step = (n / len);\n\t\tfor(int j = 0; j < (len >> 1); j++)\n\t\t\tfor(int i = 0; i < n; i += len)\n\t\t\t{\n\t\t\t\tcomplex_base u = a[i + j], v = root[step * j] * a[i + j + (len >> 1)];\n\t\t\t\ta[i + j] = u + v;\n\t\t\t\ta[i + j + (len >> 1)] = u - v;\n\t\t\t}\n\t}\n}\n\nvoid inv_fft(complex_base *a, int lg)\n{\n\tint n = (1 << lg);\n\tif(ilast_n_fft != n)\n\t{\n\t\tdouble ang = -2 * PI / n;\n\t\tfor(int i = 0; i < (n >> 1); i++)\n\t\t\tiroot[i] = complex_base(cos(ang * i), sin(ang * i));\n\n\t\tilast_n_fft = n;\n\t}\n\n\tfor(int i = 1; i < n; i++)\n\t{\n\t\tbit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));\n\t\tif(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]);\n\t}\n\n\tfor(int len = 2; len <= n; len <<= 1)\n\t{\n\t\tint step = (n / len);\n\t\tfor(int j = 0; j < (len >> 1); j++)\n\t\t\tfor(int i = 0; i < n; i += len)\n\t\t\t{\n\t\t\t\tcomplex_base u = a[i + j], v = iroot[step * j] * a[i + j + (len >> 1)];\n\t\t\t\ta[i + j] = u + v;\n\t\t\t\ta[i + j + (len >> 1)] = u - v;\n\t\t\t}\n\t}\n\n\tfor(int i = 0; i < n; i++)\n\t\ta[i] /= n;\n}\n\ncomplex_base A[MAXN], B[MAXN];\n\nvector<int> mult(vector<int> a, vector<int> b)\n{\n\tif(a.size() * b.size() <= 256)\n\t{\n\t\tvector<int> ans(a.size() + b.size(), 0);\n\t\tfor(int i = 0; i < (int)a.size(); i++)\n\t\t\tfor(int j = 0; j < (int)b.size(); j++)\n\t\t\t\tans[i + j] += a[i] * b[j];\n\n\t\treturn ans;\n\t}\n\n\tint lg = 0; while((1 << lg) < (int)(a.size() + b.size())) ++lg;\n\tfor(int i = 0; i < (1 << lg); i++) A[i] = B[i] = complex_base(0, 0);\n\tfor(int i = 0; i < (int)a.size(); i++) A[i] = complex_base(a[i], 0);\n\tfor(int i = 0; i < (int)b.size(); i++) B[i] = complex_base(b[i], 0);\n\n\tfft(A, lg); fft(B, lg);\n\tfor(int i = 0; i < (1 << lg); i++)\n\t\tA[i] = A[i] * B[i];\n\tinv_fft(A, lg);\n\n\tvector<int> ans(a.size() + b.size(), 0);\n\tfor(int i = 0; i < (int)ans.size(); i++)\n\t\tans[i] = (int)(A[i].x + 0.5);\n\n\treturn ans;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/math/fft_mod.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\ntemplate<class T, class T2> inline void chkmax(T &x, const T2 &y) { if(x < y) x = y; }\ntemplate<class T, class T2> inline void chkmin(T &x, const T2 &y) { if(x > y) x = y; }\nconst double PI = acos(-1);\nconst int MAXN = (1 << 19);\nint mod;\n\ninline void addmod(int& x, int y, int mod) { (x += y) >= mod && (x -= mod); }\ninline int mulmod(int x, int y, int mod) { return x * 1ll * y % mod; }\n\nstruct complex_base\n{\n\tdouble x, y;\n\tcomplex_base(double _x = 0, double _y = 0) { x = _x; y = _y; }\n\tfriend complex_base operator-(const complex_base &a, const complex_base &b) { return complex_base(a.x - b.x, a.y - b.y); }\n\tfriend complex_base operator+(const complex_base &a, const complex_base &b) { return complex_base(a.x + b.x, a.y + b.y); }\n\tfriend 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); }\n\tfriend void operator/=(complex_base &a, const double &P) { a.x /= P; a.y /= P; }\n};\n\nint bit_rev[MAXN];\nint last_n_fft = -1, ilast_n_fft = -1;\ncomplex_base root[MAXN], iroot[MAXN];\n\nvoid fft(complex_base *a, int lg)\n{\n\tint n = (1 << lg);\n\tif(last_n_fft != n)\n\t{\n\t\tdouble ang = 2 * PI / n;\n\t\tfor(int i = 0; i < (n >> 1); i++)\n\t\t\troot[i] = complex_base(cos(ang * i), sin(ang * i));\n\n\t\tlast_n_fft = n;\n\t}\n\n\tfor(int i = 1; i < n; i++)\n\t{\n\t\tbit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));\n\t\tif(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]);\n\t}\n\n\tfor(int len = 2; len <= n; len <<= 1)\n\t{\n\t\tint step = (n / len);\n\t\tfor(int j = 0; j < (len >> 1); j++)\n\t\t\tfor(int i = 0; i < n; i += len)\n\t\t\t{\n\t\t\t\tcomplex_base u = a[i + j], v = root[step * j] * a[i + j + (len >> 1)];\n\t\t\t\ta[i + j] = u + v;\n\t\t\t\ta[i + j + (len >> 1)] = u - v;\n\t\t\t}\n\t}\n}\n\nvoid inv_fft(complex_base *a, int lg)\n{\n\tint n = (1 << lg);\n\tif(ilast_n_fft != n)\n\t{\n\t\tdouble ang = -2 * PI / n;\n\t\tfor(int i = 0; i < (n >> 1); i++)\n\t\t\tiroot[i] = complex_base(cos(ang * i), sin(ang * i));\n\n\t\tilast_n_fft = n;\n\t}\n\n\tfor(int i = 1; i < n; i++)\n\t{\n\t\tbit_rev[i] = (bit_rev[i >> 1] >> 1) | ((i & 1) << (lg - 1));\n\t\tif(bit_rev[i] < i) swap(a[i], a[bit_rev[i]]);\n\t}\n\n\tfor(int len = 2; len <= n; len <<= 1)\n\t{\n\t\tint step = (n / len);\n\t\tfor(int j = 0; j < (len >> 1); j++)\n\t\t\tfor(int i = 0; i < n; i += len)\n\t\t\t{\n\t\t\t\tcomplex_base u = a[i + j], v = iroot[step * j] * a[i + j + (len >> 1)];\n\t\t\t\ta[i + j] = u + v;\n\t\t\t\ta[i + j + (len >> 1)] = u - v;\n\t\t\t}\n\t}\n\n\tfor(int i = 0; i < n; i++)\n\t\ta[i] /= n;\n}\n\ncomplex_base A[MAXN], B[MAXN];\n\nvector<int> mult(const vector<int> &a, const vector<int> &b)\n{\n\tif(a.size() * b.size() <= 128)\n\t{\n\t\tvector<int> ans(a.size() + b.size(), 0);\n\t\tfor(int i = 0; i < (int)a.size(); i++)\n\t\t\tfor(int j = 0; j < (int)b.size(); j++)\n\t\t\t\tans[i + j] = (ans[i + j] + a[i] * 1ll * b[j]) % mod;\n\n\t\treturn ans;\n\t}\n\n\tint lg = 0; while((1 << lg) < (int)(a.size() + b.size())) ++lg;\n\tfor(int i = 0; i < (1 << lg); i++) A[i] = B[i] = complex_base(0, 0);\n\tfor(int i = 0; i < (int)a.size(); i++) A[i] = complex_base(a[i], 0);\n\tfor(int i = 0; i < (int)b.size(); i++) B[i] = complex_base(b[i], 0);\n\n\tfft(A, lg); fft(B, lg);\n\tfor(int i = 0; i < (1 << lg); i++)\n\t\tA[i] = A[i] * B[i];\n\tinv_fft(A, lg);\n\n\tvector<int> ans(a.size() + b.size(), 0);\n\tfor(int i = 0; i < (int)ans.size(); i++)\n\t\tans[i] = (int64_t)(A[i].x + 0.5) % mod;\n\n\treturn ans;\n}\n\nvector<int> mult_mod(const vector<int> &a, const vector<int> &b)\n{\n\t/// Thanks pavel.savchenkov\n\n\t// a = a0 + sqrt(MOD) * a1\n\t// a = a0 + base * a1\n\tint base = (int)sqrtl(mod);\n\n\tvector<int> a0(a.size()), a1(a.size());\n\tfor(int i = 0; i < (int)a.size(); i++) \n\t{\n\t\ta0[i] = a[i] % base;\n\t\ta1[i] = a[i] / base;\n\t}\n\n\tvector<int> b0(b.size()), b1(b.size());\n\tfor(int i = 0; i < (int)b.size(); i++)\n\t{\n\t\tb0[i] = b[i] % base;\n\t\tb1[i] = b[i] / base;\n\t}\n\n\tvector<int> a01 = a0;\n\tfor(int i = 0; i < (int)a.size(); i++) \n\t\taddmod(a01[i], a1[i], mod);  \t\n\n\tvector<int> b01 = b0;\n\tfor(int i = 0; i < (int)b.size(); i++) \n\t\taddmod(b01[i], b1[i], mod);\n\n\tvector<int> C = mult(a01, b01);  // 1\n\n\tvector<int> a0b0 = mult(a0, b0); // 2\n\tvector<int> a1b1 = mult(a1, b1); // 3\n\n\tvector<int> mid = C;\n\tfor(int i = 0; i < (int)mid.size(); i++) \n\t{\n\t\taddmod(mid[i], -a0b0[i] + mod, mod);\n\t\taddmod(mid[i], -a1b1[i] + mod, mod);\n\t}\n\n\tvector<int> res = a0b0;\n\tfor(int i = 0; i < (int)res.size(); i++)\n\t\taddmod(res[i], mulmod(base, mid[i], mod), mod);\n\n\tbase = mulmod(base, base, mod);\n\tfor(int i = 0; i < (int)res.size(); i++)\n\t\taddmod(res[i], mulmod(base, a1b1[i], mod), mod);\n\n\treturn res;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/math/fft_xor.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\ntypedef vector<int> polynomial; \n\nvoid fft(polynomial &a, int low, int high)\n{\n\tif(low == high - 1)\n\t\treturn;\n\n\tint len = (high - low) / 2, mid = low + len;\n\tfft(a, low, mid);\n\tfft(a, mid, high);\n\n\tfor(int i = low; i < mid; i++)\n\t{\n\t\tint x1 = a[i];\n\t\tint x2 = a[i + len];\n\n\t\ta[i] = (x1 - x2);\n\t\ta[i + len] = (x1 + x2);\n\t}\n}\n\nvoid inv_fft(polynomial &a, int low, int high)\n{\n\tif(low == high - 1)\n\t\treturn;\n\n\tint len = (high - low) / 2, mid = low + len;\n\n\tfor(int i = low; i < mid; i++)\n\t{\n\t\tint y1 = a[i];\n\t\tint y2 = a[i + len];\n\n\t\ta[i] = (y1 + y2) / 2;\n\t\ta[i + len] = (y2 - y1) / 2;\n\t}\n\t\n\tinv_fft(a, low, mid);\n\tinv_fft(a, mid, high);\n}\n\nvoid read()\n{\n\t\n}\n\nvoid solve()\n{\n\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/math/fft_xor_mod.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n#define pow mypow\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int mod = (int)1e9 + 7;\nint INV2;\n\ntypedef vector<int> polynomial;\n\nint pow(int x, int p)\n{\n\tif(p == 0) return 1;\n\n\tif(p % 2 == 0)\n\t{\n\t\tint d = pow(x, p / 2);\n\t\treturn (d * d) % mod;\n\t}\n\n\treturn (pow(x, p - 1) * x) % mod;\n}\n\nint inv(int x, int mod) { return pow(x, mod - 2); }\n\nvoid fft(polynomial &a, int low, int high)\n{\n\tif(high == low + 1)\n\t\treturn;\n\n\tint len = (high - low) >> 1, mid = low + len;\n\tfft(a, low, mid);\n\tfft(a, mid, high);\n\n\tfor(int i = low; i < mid; i++)\n\t{\n\t\tint x1 = a[i] % mod;\n\t\tint x2 = a[i + len] % mod;\n\n\t\ta[i] = (x1 - x2 + mod) % mod;\n\t\ta[i + len] = (x1 + x2) % mod;\n\t}\n}\n\nvoid inv_fft(polynomial &a, int low, int high)\n{\n\tif(high == low + 1)\n\t\treturn;\n\n\tint len = (high - low) >> 1, mid = low + len;\n\n\tfor(int i = low; i < mid; i++)\n\t{\n\t\tint y1 = a[i] % mod;\n\t\tint y2 = a[i + len] % mod;\n\n\t\ta[i] = ((y1 + y2) * INV2) % mod;\n\t\ta[i + len] = ((y2 - y1 + mod) * INV2) % mod;\n\t}\n\t\n\tinv_fft(a, low, mid);\n\tinv_fft(a, mid, high);\n}\n\nvoid read()\n{\n\t\n}\n\nvoid solve()\n{\n\tINV2 = inv(2, mod);\n\tcout << INV2 << endl;\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/math/gauss_elimination_equations.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst double eps = 1e-9;\n\nvector<double> gauss(vector<vector<double>> &a)\n{\n\tint n = a.size(), m = a[0].size() - 1;\n\n\tvector<int> where(m, -1);\n\tfor(int col = 0, row = 0; col < m && row < n; col++)\n    {\n    \tint sel = row;\n        for(int i = row; i < n; i++)\n        \tif(abs(a[i][col]) > abs(a[sel][col]))\n        \t\tsel = i;\n\n\t\tif(abs(a[sel][col]) < eps) { where[col] = -1; continue; }\n\n        for(int i = col; i <= m; i++)\n\t\t\tswap(a[sel][i], a[row][i]);\n\t\twhere[col] = row;\n\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tif(i != row)\n\t\t\t{\n\t\t\t\tif(abs(a[i][col]) < eps) continue;\n            \tdouble c = a[i][col] / a[row][col];\n            \tfor(int j = 0; j <= m; j++)\n                    a[i][j] -= c * a[row][j];\n\t\t\t}\n\n\t\trow++;\n    }\n\n    vector<double> ans(m, 0);\n    for(int i = 0; i < m; i++)\n        if(where[i] != -1)\n\t\t\tans[i] = a[where[i]][m] / a[where[i]][i];\n\n    for(int i = 0; i < n; i++)\n\t{\n\t\tdouble sum = a[i][m];\n\t\tfor(int j = 0; j < m; j++)\n\t\t\tsum -= ans[j] * a[i][j];\n\n\t\tif(abs(sum) > eps) return vector<double>();\n\t}\n\n\treturn ans;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/math/gauss_elimination_equations_mod.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int64_t mod = (int64_t)1e9 + 7;\n\nint64_t pow(int64_t base, int64_t p, int64_t MOD)\n{\n\tif(p == 0) return 1;\n\tif(p % 2 == 0) { int64_t d = pow(base, p / 2, MOD); return (d * d) % MOD; }\n\treturn (pow(base, p - 1, MOD) * base) % MOD;\n}\n\nint64_t inv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); }\n\nvector<int64_t> gauss(vector<vector<int64_t>> &a, int64_t MOD)\n{\n\tint n = a.size(), m = a[0].size() - 1;\n\n\tfor(int i = 0; i < n; i++)\n\t\tfor(int j = 0; j <= m; j++)\n\t\t\ta[i][j] = (a[i][j] % MOD + MOD) % MOD;\n\n\tvector<int> where(m, -1);\n\tfor(int col = 0, row = 0; col < m && row < n; col++)\n    {\n    \tint sel = row;\n        for(int i = row; i < n; i++)\n        \tif(a[i][col] > a[sel][col])\n        \t\tsel = i;\n\n\t\tif(a[sel][col] == 0) { where[col] = -1; continue; }\n\n        for(int i = col; i <= m; i++)\n\t\t\tswap(a[sel][i], a[row][i]);\n\t\twhere[col] = row;\n\n\t\tint64_t c_inv = inv(a[row][col], MOD);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tif(i != row)\n\t\t\t{\n\t\t\t\tif(a[i][col] == 0) continue;\n            \tint64_t c = (a[i][col] * c_inv) % MOD;\n            \tfor(int j = 0; j <= m; j++)\n                    a[i][j] = (a[i][j] - c * a[row][j] % MOD + MOD) % MOD;\n\t\t\t}\n\n\t\trow++;\n    }\n\n    vector<int64_t> ans(m, 0);\n    for(int i = 0; i < m; i++)\n        if(where[i] != -1)\n\t\t\tans[i] = (a[where[i]][m] * inv(a[where[i]][i], MOD)) % MOD;\n\n    for(int i = 0; i < n; i++)\n\t{\n\t\tint64_t sum = a[i][m] % MOD;\n\t\tfor(int j = 0; j < m; j++)\n\t\t\tsum = (sum + MOD - (ans[j] * a[i][j]) % MOD) % MOD;\n\n\t\tif(sum != 0) return vector<int64_t>();\n\t}\n\n\treturn ans;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/math/gauss_elimination_equations_mod_number_solutions.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int64_t mod = (int64_t)1e9 + 7;\n\nint64_t pow(int64_t base, int64_t p, int64_t MOD)\n{\n\tif(p == 0) return 1;\n\tif(p % 2 == 0) { int64_t d = pow(base, p / 2, MOD); return (d * d) % MOD; }\n\treturn (pow(base, p - 1, MOD) * base) % MOD;\n}\n\nint64_t inv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); }\n\nint64_t gauss(vector<vector<int64_t>> &a, int64_t MOD)\n{\n\tint n = a.size(), m = a[0].size() - 1;\n\n\tfor(int i = 0; i < n; i++)\n\t\tfor(int j = 0; j <= m; j++)\n\t\t\ta[i][j] = (a[i][j] % MOD + MOD) % MOD;\n\n\tvector<int> where(m, -1);\n\tfor(int col = 0, row = 0; col < m && row < n; col++)\n    {\n    \tint sel = row;\n        for(int i = row; i < n; i++)\n        \tif(a[i][col] > a[sel][col])\n        \t\tsel = i;\n\n\t\tif(a[sel][col] == 0) { where[col] = -1; continue; }\n\n        for(int i = col; i <= m; i++)\n\t\t\tswap(a[sel][i], a[row][i]);\n\t\twhere[col] = row;\n\n\t\tint64_t c_inv = inv(a[row][col], MOD);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tif(i != row)\n\t\t\t{\n\t\t\t\tif(a[i][col] == 0) continue;\n            \tint64_t c = (a[i][col] * c_inv) % MOD;\n            \tfor(int j = 0; j <= m; j++)\n                    a[i][j] = (a[i][j] - c * a[row][j] % MOD + MOD) % MOD;\n\t\t\t}\n\n\t\trow++;\n    }\n\n    vector<int64_t> ans(m, 0);\n    int64_t result = 1;\n\n    for(int i = 0; i < m; i++)\n        if(where[i] != -1) ans[i] = (a[where[i]][m] * inv(a[where[i]][i], MOD)) % MOD;\r\n\t\telse result = (result * MOD) % mod;\n\n    for(int i = 0; i < n; i++)\n\t{\n\t\tint64_t sum = a[i][m] % MOD;\n\t\tfor(int j = 0; j < m; j++)\n\t\t\tsum = (sum + MOD - (ans[j] * a[i][j]) % MOD) % MOD;\n\n\t\tif(sum != 0) return 0;\n\t}\n\n\treturn result;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/math/matrix_exponential.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int mod = (int)1e9 + 7;\nconst int64_t inf = (int64_t)1e16 + 42;\n\ntemplate<class T>\nstruct matrix\n{\n\tint n;\n\tvector<vector<T> > t;\n\n\tmatrix(int _n, T val) {n = _n; t.assign(n, vector<T>(n, val)); }\n\tmatrix(int _n) {n = _n; t.assign(n, vector<T>(n, 0)); }\n    matrix() { n = 0; t.clear(); }\n\n\tmatrix operator * (matrix b)\n\t{\n\t\tmatrix c = matrix(n, 0);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tfor(int k = 0; k < n; k++)\n\t\t\t\tfor(int j = 0; j < n; j++)\n\t\t\t\t\tc.t[i][j] = (c.t[i][j] + t[i][k] * b.t[k][j]) % mod;\n\t\treturn c;\n\t}\n\n\tvector<T> operator * (vector<T> b)\n\t{\n\t\tvector<T> c = vector<T>(n, 0);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tfor(int j = 0; j < n; j++)\n                c[i] = (c[i] + t[i][j] * b[j]) % mod;\n\n\t\treturn c;\n\t}\n\n\tmatrix<T> operator ^ (matrix<T> b)\n\t{\n\t\tmatrix<T> c = matrix(n, inf);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tfor(int k = 0; k < n; k++)\n\t\t\t\tfor(int j = 0; j < n; j++)\n\t\t\t\t\tc.t[i][j] = min(c.t[i][j], t[i][k] + b.t[k][j]);\n\t\treturn c;\n\t}\n\n\tmatrix<T> operator + (matrix<T> b)\n\t{\n\t\tmatrix<T> c = matrix<T>(n);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tfor(int j = 0; j < n; j++)\n\t\t\t\tc.t[i][j] =  (t[i][j] + b.t[i][j]) % mod;\n\n\t\treturn c;\n\t}\n\n\tmatrix<T> operator - (matrix<T> b)\n\t{\n\t\tmatrix<T> c = matrix<T>(n);\n\t\tfor(int i = 0; i < n; i++)\n            for(int j = 0; j < n; j++)\n\t\t\t\tc.t[i][j] = (t[i][j] - b.t[i][j] + mod) % mod;\n\n\t\treturn c;\n\t}\n\n\tmatrix operator & (matrix b)\n\t{\n\t\tmatrix<T> c = matrix<T>(n, -inf);\n\t\tfor(int i = 0; i < n; i++)\n\t\t\tfor(int k = 0; k < n; k++)\n\t\t\t\tfor(int j = 0; j < n; j++)\n\t\t\t\t\tc.t[i][j] = max(c.t[i][j], t[i][k] + b.t[k][j]);\n\n\t\treturn c;\n\t}\n};\n\ntemplate<class T>\nmatrix<T> pow_min(matrix<T> base, int64_t p)\n{\n\tif(p == 1) return base;\n\n\tif(p % 2ll == 0ll)\n\t{\n\t\tmatrix<T> d = pow_min(base, p / 2ll);\n\t\treturn d ^ d;\n\t}\n\n\treturn base ^ pow_min(base, p - 1);\n}\n\ntemplate<class T>\nmatrix<T> pow_max(matrix<T> base, int64_t p)\n{\n\tif(p == 1) return base;\n\n\tif(p % 2ll == 0ll)\n\t{\n\t\tmatrix<T> d = pow_max(base, p / 2ll);\n\t\treturn d & d;\n\t}\n\n\treturn base & pow_max(base, p - 1);\n}\n\ntemplate<class T>\nmatrix<T> pow(matrix<T> base, int64_t p)\n{\n\tif(p == 1) return base;\n\n\tif(p % 2ll == 0ll)\n\t{\n\t\tmatrix<T> d = pow(base, p / 2ll);\n\t\treturn d * d;\n\t}\n\n\treturn base * pow(base, p - 1);\n}\n\ntemplate<class T>\nvoid print(matrix<T> mat)\n{\n\tfor(int i = 0; i < mat.n; i++)\n\t\tfor(int j = 0; j < mat.n; j++)\n\t\t\tif(mat.t[i][j] < inf) cout << mat.t[i][j] << \" \\n\"[j == mat.n - 1];\n\t\t\telse cout << \"inf\" << \" \\n\"[j == mat.n - 1];\n\n\tcout << endl;\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/math/number_theory.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int bound = 1000000;\nconst int64_t mod = (int64_t)1e9 + 7;\n\nint64_t pow(int64_t x, int64_t p, int64_t MOD)\n{\n    if(p == 0) return 1;\n    if(p % 2 == 1) return (x * pow(x, p - 1, MOD)) % MOD;\n    int64_t half = pow(x, p / 2, MOD);\n    return (half * half) % MOD;\n}\n\nint lp[bound + 1], phi[bound + 1];\nvector<int> pr;\n\ntemplate<class T>\nvector<T> get_divs(T x)\n{\n    if(x <= bound)\n    {\n        vector<T> ret;\n        while(x != 1) { ret.push_back(lp[x]); x /= lp[x]; }\n        return ret;\n    }\n\n    vector<T> ret;\n    for(T d = 2; d * 1ll * d <= x; d++)\n        while(x % d == 0) ret.push_back(d), x /= d;\n\n    if(x != 1) ret.push_back(x);\n    return ret;\n}\n\nint64_t gcd(int64_t a, int64_t b, int64_t &x, int64_t &y)\n{\n\tif(a == 0)\n\t{\n\t\tx = 0;\n\t\ty = 1;\n\t\treturn b;\n\t}\n\n\tint64_t x1, y1, g = gcd(b % a, a, x1, y1);\n\tx = y1 - (b / a) * x1;\n\ty = x1;\n\n\treturn g;\n}\n\nvoid prepare()\n{\n    phi[1] = 1;\n    for(int i = 2; i <= bound; i++)\n    {\n        if(lp[i] == 0) lp[i] = i, phi[i] = i - 1, pr.push_back(i);\n        else if(lp[i] == lp[i / lp[i]]) phi[i] = phi[i / lp[i]] * lp[i];\n        else phi[i] = phi[i / lp[i]] * (lp[i] - 1);\n        for(int j = 0; j < pr.size() && i * 1ll * pr[j] <= bound && pr[j] <= lp[i]; j++)\n            lp[i * pr[j]] = pr[j];\n    }\n}\n\nint64_t gcd(int64_t a, int64_t b)\n{\n    if(a == 0 || b == 0) return a + b;\n    return __gcd(a, b);\n}\n\nint64_t get_phi(int64_t x)\n{\n    int64_t cop = x, ret = x;\n    for(int64_t div = 2; div * div <= cop; div++)\n        if(cop % div == 0)\n        {\n            while(cop % div == 0) cop /= div;\n            ret /= div;\n            ret *= (div - 1);\n        }\n\n    if(cop != 1) ret /= cop, ret *= (cop - 1);\n    return ret;\n}\n\nint64_t pinv(int64_t x, int64_t MOD) { return pow(x, MOD - 2, MOD); }\n\nint64_t inv(int64_t x, int64_t MOD)\n{\n    if(gcd(x, MOD) != 1) return -1;\n    if(MOD <= bound) return pow(x, phi[MOD] - 1, MOD);\n    return pow(x, get_phi(MOD) - 1, MOD);\n}\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "old_impl/strings/aho_corasick.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct aho_corasick\n{\n\tint is_end[MAXN], link[MAXN], psz;\n\tmap<char, int> to[MAXN];\n\n\tvoid clear()\n\t{\n\t\tfor(int i = 0; i < psz; i++)\n\t\t\tis_end[i] = 0, link[i] = 0, to[i].clear();\n\t\t\n\t\tpsz = 1;\n\t\tis_end[0] = 1;\n\t}\n\n\taho_corasick() { psz = MAXN - 2; clear(); }\n\n\tvoid add_word(string s)\n\t{\n\t\tint u = 0;\n\t\tfor(char c: s)\n\t\t{\n\t\t\tif(!to[u].count(c)) to[u][c] = psz++;\n\t\t\tu = to[u][c];\n\t\t}\n\n\t\tis_end[u] = 1;\n\t}\n\n\tvoid push_links()\n\t{\n\t\tqueue<int> Q;\n\t\tint u, v, j; \n\t\tchar c;\n\t\t\n\t\tQ.push(0);\n\t\tlink[0] = -1;\n\t\t\n\t\twhile(!Q.empty())\n\t\t{\n\t\t\tu = Q.front();\n\t\t\tQ.pop();\n\n\t\t\tfor(auto it: to[u])\n\t\t\t{\n\t\t\t\tv = it.second;\n\t\t\t\tc = it.first;\n\t\t\t\tj = link[u];\n\t\t\t\n\t\t\t\twhile(j != -1 && !to[j].count(c)) j = link[j];\n\t\t\t\tif(j != -1) link[v] = to[j][c];\n\t\t\t\telse link[v] = 0;\n\t\t\t\n\t\t\t\tQ.push(v);\n\t\t\t}\n\t\t}\n\t}\n};\n\nint n, m;\nstring s[MAXN];\n\nvoid read()\n{\n\tcin >> n >> m;\n\tfor(int i = 0; i < m; i++)\n\t\tcin >> s[i];\n}\n\naho_corasick aho;\n\nvoid solve()\n{\n\taho.clear();\n\tfor(int i = 0; i < m; i++)\n\t\taho.add_word(s[i]);\n\taho.push_links();\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/aho_corasick_dynamic.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct aho_corasick_static\n{\n\tint cnt[MAXN], len[MAXN], link[MAXN], psz;\n\tmap<char, int> to[MAXN];\n\n\tvoid clear()\n\t{\n\t\tfor(int i = 0; i < psz; i++)\n\t\t\tcnt[i] = 0, len[i] = 0, link[i] = -1, to[i].clear();\n\n\t\tpsz = 1;\n\t\tlink[0] = -1;\n\t\tcnt[0] = 0;\n\t}\n\n\taho_corasick_static() { psz = MAXN - 2; clear(); }\n\n\tvoid add_word(string s)\n\t{\n\t\tint u = 0;\n\t\tfor(char c: s)\n\t\t{\n\t\t\tif(!to[u].count(c)) to[u][c] = psz++, len[psz - 1] = len[u] + 1;\n\t\t\tu = to[u][c];\n\t\t}\n\n\t\tcnt[u]++;\n\t}\n\n\tvoid push_links()\n\t{\n\t\tqueue<int> Q;\n\t\tint u, v, j; \n\t\tchar c;\n\n\t\tQ.push(0);\n\t\tlink[0] = -1;\n\n\t\twhile(!Q.empty())\n\t\t{\n\t\t\tu = Q.front();\n\t\t\tQ.pop();\n\n\t\t\tfor(auto it: to[u])\n\t\t\t{\n\t\t\t\tv = it.second;\n\t\t\t\tc = it.first;\n\t\t\t\tj = link[u];\n\n\t\t\t\twhile(j != -1 && !to[j].count(c)) j = link[j];\n\t\t\t\tif(j != -1) link[v] = to[j][c];\n\t\t\t\telse link[v] = 0;\n\n\t\t\t\tcnt[v] += cnt[link[v]];\n\t\t\t\tQ.push(v);\n\t\t\t}\n\t\t}\n\t}\n\n\tint count(string p)\n\t{\n\t\tint u = 0, ans = 0;\n\t\tfor(char c: p)\n\t\t{\n\t\t\twhile(u != -1 && !to[u].count(c)) u = link[u];\n\t\t\tif(u == -1) u = 0;\n\t\t\telse u = to[u][c];\n\t\t\tans += cnt[u];\n\t\t}\t\t\n\n\t\treturn ans;\n\t}\n};\n\nstruct aho_corasick\n{\n\tvector<string> li[20];\n\taho_corasick_static ac[20];\n\n\tvoid clear() \n\t{ \n\t\tfor(int i = 0; i < 20; i++) \n\t\t{\n\t\t\tli[i].clear();\n\t\t\tac[i].clear();\n\t\t}\n\t}\n\n\taho_corasick() { clear(); }\n\n\tvoid add_word(string s)\n\t{\n\t\tint pos = 0;\n\t\tfor(int l = 0; l < 20; l++)\n\t\t\tif(li[l].empty())\n\t\t\t{\n\t\t\t\tpos = l;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\tli[pos].push_back(s);\n\t\tac[pos].add_word(s);\n\n\t\tfor(int bef = 0; bef < pos; bef++)\n\t\t{\n\t\t\tac[bef].clear();\n\t\t\tfor(string s2: li[bef])\n\t\t\t{\n\t\t\t\tli[pos].push_back(s2);\n\t\t\t\tac[pos].add_word(s2);\n\t\t\t}\n\t\t\t\n\t\t\tli[bef].clear();\n\t\t}\n\n\t\tac[pos].push_links();\n\t}\n\n\tint count(string s)\n\t{\n\t\tint ans = 0;\n\t\tfor(int l = 0; l < 20; l++)\n\t\t\tans += ac[l].count(s);\n\n\t\treturn ans;\n\t}\n};\n\nint m;\nstring s[MAXN];\n\nvoid read()\n{\n\tcin >> m;\n\tfor(int i= 0; i < m; i++)\n\t\tcin >> s[i];\n}\n\naho_corasick aho;\n\nvoid solve()\n{\n\taho.clear();\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\taho.add_word(s[i]);\n\t\tcout << aho.count(\"aaaaaasssaaa\") << endl;\n\t}\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/kmp.cpp",
    "content": "#include <bits/stdc++.h>\r\n#define endl '\\n'\r\n\r\nusing namespace std;\r\nconst int MAXN = (1 << 20);\r\n\r\nstring str, pat;\r\n\r\nvoid read() {\r\n    cin >> str;\r\n    cin >> pat;\r\n}\r\n\r\nvector<int> failure_function(string p) {\r\n    int sz = p.size();\r\n    vector<int> f;\r\n    f.assign(sz + 1, 0);\r\n\r\n    int j = 0;\r\n    f[0] = 0;\r\n\r\n    for(int i = 1; i < sz; i++) {\r\n        while(j >= 0 && p[i] != p[j]) {\r\n            if(j >= 1) {\r\n                j = f[j - 1];\r\n            } else {\r\n                j = -1;\r\n            }\r\n        }\r\n\r\n        j++;\r\n        f[i] = j;\r\n    }\r\n\r\n    return f;\r\n}\r\n\r\nvoid match(vector<int> f, string p, string s) {\r\n    int psz = p.size(), sz = s.size();\r\n\r\n    int j = 0;\r\n    for(int i = 0; i < sz; i++) {\r\n        while(j >= 0 && p[j] != s[i]) {\r\n            if(j >= 1) {\r\n                j = f[j - 1];\r\n            } else {\r\n                j = -1;\r\n            }\r\n        }\r\n\r\n        j++;\r\n        if(j == psz) {\r\n            j = f[j - 1];\r\n            cout << \"Found pattern in [\" << i - psz + 1 << \"; \" << i << \"]\"\r\n                 << endl;\r\n        }\r\n    }\r\n}\r\n\r\nvector<int> f;\r\n\r\nvoid solve() {\r\n    f = failure_function(pat);\r\n    match(f, pat, str);\r\n}\r\n\r\nint main() {\r\n    ios_base::sync_with_stdio(false);\r\n    cin.tie(NULL);\r\n\r\n    read();\r\n    solve();\r\n    return 0;\r\n}\r\n"
  },
  {
    "path": "old_impl/strings/palindromic_tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct palindromic_tree\n{\n\tint s[MAXN], len[MAXN], link[MAXN];\n\tmap<char, int> to[MAXN]; \n\tint n, last, psz;\n \n\tvoid clear()\n\t{\t\t\n\t\ts[n++] = -1;\n\t\tlink[0] = 1;\n\t\tlen[1] = -1;\n\t\tpsz = 2;\n\t}\n \n\tint get_link(int v)\t\n\t{\n\t\twhile(s[n - len[v] - 2] != s[n - 1]) \n\t\t\tv = link[v];\n\t\treturn v;\n\t}\n \n\tvoid add_letter(char c)\t\n\t{\n\t\ts[n++] = c;\n\t\tlast = get_link(last);\n\t\t\n\t\tif(!to[last][c])\n\t\t{\n\t\t\tlen[psz] = len[last] + 2;\n\t\t\tlink[psz] = to[get_link(link[last])][c];\n\t\t\tto[last][c] = psz++;\n\t\t}\n\t\t\n\t\tlast = to[last][c];\n\t}\n};\n\nvoid read()\n{\n\t\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/rabin_karp.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct rabin_karp\n{\n\tint mod, base, sz, len;\n\tint h[MAXN], base_pow[MAXN];\n\n\tvoid init(string s, int _base, int _mod)\n\t{\n\t\tmod = _mod;\n\t\tbase = _base;\n\t\tsz = s.size();\n\t\n\t\th[0] = 0;\t\n\t\tfor(int i = 1; i <= sz; i++)\n\t\t\th[i] = (h[i - 1] * base + s[i - 1]) % mod;\n\t\t\n\t\tbase_pow[0] = 1;\n\t\tfor(int i = 1; i <= sz; i++)\n\t\t\tbase_pow[i] = (base_pow[i - 1] * base) % mod;\n\t}\n\n\tint get_hash(int l, int r)\n\t{\n\t\tlen = r - l + 1;\n\t\treturn (h[r] - (h[l - 1] * base_pow[len]) % mod + mod) % mod;\n\t}\n};\n\nvoid read()\n{\n\t\n}\n\nvoid solve()\n{\n\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/suffix_array.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (int)1e5 + 42;\nconst int MAXLOG = 20;\n\nstruct suffix_array {\n    pair<pair<int, int>, int> L[MAXN];\n    int P[MAXLOG + 1][MAXN], n, stp, cnt, sa[MAXN];\n\n    suffix_array() {\n        n = 0;\n        stp = 0;\n        cnt = 0;\n    }\n\n    suffix_array(const string &s) : n(s.size()) {\n        for(int i = 0; i < n; i++) {\n            P[0][i] = s[i];\n        }\n\n        sa[0] = 0;\n        for(stp = 1, cnt = 1; cnt < n; stp++, cnt <<= 1) {\n            for(int i = 0; i < n; i++) {\n                L[i] = {\n                    {P[stp - 1][i], i + cnt < n ? P[stp - 1][i + cnt] : -1}, i\n                };\n            }\n\n            sort(L, L + n);\n            for(int i = 0; i < n; i++) {\n                P[stp][L[i].second] = i > 0 && L[i].first == L[i - 1].first\n                                          ? P[stp][L[i - 1].second]\n                                          : i;\n            }\n        }\n\n        for(int i = 0; i < n; i++) {\n            sa[i] = L[i].second;\n        }\n    }\n\n    int &operator[](int idx) { return sa[idx]; }\n\n    int lcp(int x, int y) {\n        int k, ret = 0;\n        if(x == y) {\n            return n - x;\n        }\n        for(k = stp - 1; k >= 0 && x < n && y < n; k--) {\n            if(P[k][x] == P[k][y]) {\n                x += (1 << k), y += (1 << k), ret += (1 << k);\n            }\n        }\n\n        return ret;\n    }\n};\n\nstring s;\n\nvoid read() { cin >> s; }\n\nvoid solve() {\n    suffix_array sa(s);\n    for(int idx = 0; idx < (int)s.size(); idx++) {\n        cout << sa[idx] << endl;\n    }\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/strings/suffix_array_hash.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define int long long\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct rabin_karp\n{\n\tint mod, base, sz;\n\tvector<int> h, base_pow;\n\n\tvoid init(string s, int _mod, int _base)\n\t{\n\t\tmod = _mod;\n\t\tbase = _base;\n\t\tsz = s.size();\n\t\n\t\th.assign(sz + 1, 0);\n\t\tbase_pow.assign(sz + 1, 0);\n\t\n\t\tfor(int i = 1; i <= sz; i++)\n\t\t\th[i] = (h[i - 1] * base + s[i - 1]) % mod;\n\t\t\n\t\tbase_pow[0] = 1;\n\t\tfor(int i = 1; i <= sz; i++)\n\t\t\tbase_pow[i] = (base_pow[i - 1] * base) % mod;\n\t}\n\n\tint get_hash(int l, int r)\n\t{\n\t\tint len = r - l + 1;\n\t\treturn (h[r] - (h[l - 1] * base_pow[len]) % mod + mod) % mod;\n\t}\n};\n\nrabin_karp fir, sec;\nstring str;\nint sz;\n\nbool cmp(int i, int j)\n{\n\tint l = 1, r = min(sz - i, sz - j), mid, ans = 0;\n\n\twhile(l <= r)\n\t{\n\t\tmid = (l + r) >> 1;\n\n\t\tif(fir.get_hash(i + 1, i + mid) == fir.get_hash(j + 1, j + mid) && \n\t   \t   sec.get_hash(i + 1, i + mid) == sec.get_hash(j + 1, j + mid))\n\t\t{\t\n\t\t\tl = mid + 1;\n\t\t\tans = mid;\n\t\t}\n\t\telse\n\t\t\tr = mid - 1;\n\t}\t\n\n\tif(ans == min(sz - i, sz - j)) return (sz - i) < (sz - j);\n\treturn (str[i + ans] < str[j + ans]);\n}\n\nvector<int> kasai(string s, vector<int> sa)\n{\n\tsz = s.size();\n\n\tvector<int> lcp, pos;\n\tlcp.assign(sz, 0);\n\tpos.assign(sz, 0);\n\n\tfor(int i = 0; i < sz; i++)\n\t\tpos[sa[i]] = i;\n\n\tint k = 0;\n\tfor(int i = 0; i < sz; i++, k ? k-- : 0)\n\t{\n\t\tif(pos[i] == sz - 1)\n\t\t{\n\t\t\tk = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tint j = sa[pos[i] + 1];\n\t\twhile(i + k < sz && j + k < sz && s[i + k] == s[j + k]) k++;\n\t\tlcp[pos[i]] = k;\n\t}\n\n\treturn lcp;\n}\n\nvector<int> build(string s)\n{\n\tvector<int> _sa;\n\tsz = s.size();\n\tstr = s;\n\n\tfir.init(str, (int)(1e9 + 7), 131);\n\tsec.init(str, (int)(1e9 + 9), 137);\n\t\t\n\t_sa.assign(sz, 0);\n\tfor(int i = 0; i < sz; i++)\n\t\t_sa[i] = i;\n\n\tstable_sort(_sa.begin(), _sa.end(), cmp);\n\treturn _sa;\n}\t\t\n\nint n;\nstring a;\n\nvoid read()\n{\n\tcin >> a;\n\tn = a.size();\n}\n\nvector<int> sa, lcp;\n\nvoid solve()\n{\n\tsa = build(a);\n\tlcp = kasai(a, sa);\n\t\n\tcout << \"arr:  \";\n\tfor(int i = 0; i < n; i++)\n\t\tcout << sa[i] << \" \";\n\tcout << endl;\n\n\tcout << \"lcp:  \";\n\tfor(int i = 0; i < n - 1; i++)\n\t\tcout << lcp[i] << \" \";\n\tcout << endl;\n}\n\n#undef int\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/suffix_array_log2.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nint n;\nstring s;\n\nvoid read()\n{\n\tcin >> s;\n\tn = s.size();\n}\n\nint lcp[MAXN], sa[MAXN], rnk[MAXN], idx[MAXN], temp[MAXN], gap;\n\nbool cmp(int i, int j)\n{\n\tif(idx[i] != idx[j]) return idx[i] < idx[j]; i += gap; j += gap;\n\treturn (i < n && j < n) ? idx[i] < idx[j] : i > j;\n}\n\nvoid build_suffix_array()\n{\n\tfor(int i = 0; i < n; i++)\n\t{\n\t\tsa[i] = i;\n\t\tidx[i] = s[i];\n\t}\n\n\tfor(gap = 1; ; gap = gap * 2)\n\t{\n\t\tsort(sa, sa + n, cmp);\n\n\t\tfor(int i = 0; i < n - 1; i++) \n\t\t{\n\t\t\ttemp[i + 1] = temp[i];\n\t\t\ttemp[i + 1] += cmp(sa[i], sa[i + 1]);\n\t\t}\n\t\t\n\t\tfor(int i = 0; i < n; i++) \n\t\t\tidx[sa[i]] = temp[i];\n\t\t\n\t\tif(temp[n - 1] == n - 1) break;\n\t}\n}\n\nvoid build_lcp()\n{\n\tint k = 0;\n\n\tfor(int i = 0; i < n; i++)\n\t\trnk[sa[i]] = i;\n\n\tfor(int i = 0; i < n; i++, k ? k-- : 0)\n\t{\n\t\tif(rnk[i] == n - 1)\n\t\t{\n\t\t\tk = 0;\n\t\t\tcontinue;\n\t\t}\n\n\t\tint j = sa[rnk[i] + 1];\t\n\t\twhile(i + k < n && j + k < n && s[i + k] == s[j + k]) k++;\n\t\tlcp[rnk[i]] = k;\n\t}\t\n}\n\nint dp[MAXN][20];\nint logr[MAXN];\n\nvoid sparse_table()\n{\n\tfor(int i = 0; i < n; i++)\n\t\tdp[i][0] = lcp[i];\n\n\tfor(int lg = 1; (1 << lg) <= n; lg++)\n\t\tfor(int i = 0; i + (1 << lg) < n; i++)\n\t\t\tdp[i][lg] = min(dp[i][lg - 1], dp[i + (1 << (lg - 1))][lg - 1]);\n\n\tlogr[0] = -1;\n\tfor(int i = 1; i <= n; i++)\n\t\tlogr[i] = logr[i / 2] + 1;\n}\n\nint LCP(int l, int r)\n{\n\tif(l > r) return n - sa[l];\n\tint len = r - l + 1, lg = logr[len];\n\treturn min(dp[l][lg], dp[r - (1 << lg) + 1][lg]);\n}\n\nvoid prepare()\n{\n\tbuild_suffix_array();\n\tbuild_lcp();\n\tsparse_table();\n}\n\nvoid solve()\n{\n\tprepare();\n}\n\nint main()\n{\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/strings/suffix_automaton.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct suffix_automaton {\n    map<char, int> to[MAXN];\n    int len[MAXN], link[MAXN];\n    int last, psz = 0;\n\n    void add_letter(char c) {\n        int p = last, cl, q;\n        if(to[p].count(c)) {\n            q = to[p][c];\n            if(len[q] == len[p] + 1) {\n                last = q;\n                return;\n            }\n\n            cl = psz++;\n            len[cl] = len[p] + 1;\n            to[cl] = to[q];\n            link[cl] = link[q];\n            link[q] = cl;\n            last = cl;\n\n            for(; to[p][c] == q; p = link[p]) {\n                to[p][c] = cl;\n            }\n\n            return;\n        }\n\n        last = psz++;\n        len[last] = len[p] + 1;\n\n        for(; to[p][c] == 0; p = link[p]) {\n            to[p][c] = last;\n        }\n\n        if(to[p][c] == last) {\n            link[last] = p;\n            return;\n        }\n\n        q = to[p][c];\n        if(len[q] == len[p] + 1) {\n            link[last] = q;\n            return;\n        }\n\n        cl = psz++;\n        len[cl] = len[p] + 1;\n        to[cl] = to[q];\n        link[cl] = link[q];\n        link[q] = cl;\n        link[last] = cl;\n\n        for(; to[p][c] == q; p = link[p]) {\n            to[p][c] = cl;\n        }\n    }\n\n    void clear() {\n        for(int i = 0; i < psz; i++) {\n            len[i] = 0, link[i] = 0, to[i].clear();\n        }\n        psz = 1;\n        last = 0;\n    }\n\n    void init(string s) {\n        clear();\n        for(int i = 0; i < (int)s.size(); i++) {\n            add_letter(s[i]);\n        }\n    }\n\n    suffix_automaton() {\n        psz = 0;\n        clear();\n    }\n};\n\nvoid read() {}\n\nsuffix_automaton sa;\n\nvoid solve() { sa.clear(); }\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/strings/trie.cpp",
    "content": "#include <bits/stdc++.h>\n\nusing namespace std;\n\nstruct trie {\n    vector<int> cnt, len;\n    vector<map<char, int>> to;\n\n    trie() { clear(); }\n\n    void clear() {\n        cnt.assign(1, 0);\n        len.assign(1, 0);\n        to.assign(1, map<char, int>());\n    }\n\n    void add(string s) {\n        int u = 0;\n        for(char c: s) {\n            if(!to[u].count(c)) {\n                to[u][c] = len.size();\n                len.push_back(len[u] + 1);\n                cnt.push_back(0);\n                to.push_back(map<char, int>());\n            }\n            u = to[u][c];\n            cnt[u]++;\n        }\n    }\n\n    void del(string s) {\n        int u = 0;\n        for(char c: s) {\n            if(!to[u].count(c)) {\n                return;\n            }\n            u = to[u][c];\n            cnt[u]--;\n        }\n    }\n\n    int count(string s) {\n        int u = 0;\n        for(char c: s) {\n            if(!to[u].count(c)) {\n                return 0;\n            }\n            u = to[u][c];\n        }\n\n        return cnt[u];\n    }\n};\n\ntrie t;\n\nvoid read() {}\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/tree/centroid_decomposition.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nint n;\nvector<int> adj[MAXN];\n\nvoid read() {\n    cin >> n;\n    for(int i = 0; i < n - 1; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n}\n\nint tr_sz[MAXN], cnt_vers;\nbool used[MAXN];\n\nvoid pre_dfs(int u, int pr) {\n    cnt_vers++;\n    tr_sz[u] = 1;\n    for(int v: adj[u]) {\n        if(!used[v] && v != pr) {\n            pre_dfs(v, u);\n            tr_sz[u] += tr_sz[v];\n        }\n    }\n}\n\nint centroid(int u, int pr) {\n    for(int v: adj[u]) {\n        if(!used[v] && v != pr && tr_sz[v] > cnt_vers / 2) {\n            return centroid(v, u);\n        }\n    }\n\n    return u;\n}\n\nint link[MAXN];\n\nvoid decompose(int u, int pr = -1) {\n    cnt_vers = 0;\n    pre_dfs(u, u);\n    int cen = centroid(u, u);\n    link[cen] = pr;\n\n    used[cen] = true;\n    for(int v: adj[cen]) {\n        if(!used[v]) {\n            decompose(v, cen);\n        }\n    }\n    used[cen] = false;\n}\n\nvoid solve() {}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/tree/dsu_on_tree.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nint n;\nvector<int> G[MAXN];\n\nvoid read() {\n    cin >> n;\n\n    for(int i = 0; i < n - 1; i++) {\n        int u, v;\n        cin >> u >> v;\n\n        G[u].push_back(v);\n        G[v].push_back(u);\n    }\n}\n\nint tr_sz[MAXN];\n\nvoid pre_dfs(int u, int pr) {\n    tr_sz[u] = 1;\n    for(int v: G[u]) {\n        if(v != pr) {\n            pre_dfs(v, u);\n            tr_sz[u] += tr_sz[v];\n        }\n    }\n}\n\nvoid add_vertex(int u) {}\n\nvoid clear(int u, int pr) {}\n\nvoid add(int u, int pr) {\n    add_vertex(u);\n    for(int v: G[u]) {\n        if(v != pr) {\n            add(v, u);\n        }\n    }\n}\n\nvoid dfs(int u, int pr, int keep) {\n    pair<int, int> mx = {-1, -1};\n    for(int v: G[u]) {\n        if(v != pr) {\n            mx = max(mx, {tr_sz[v], v});\n        }\n    }\n\n    for(int v: G[u]) {\n        if(v != pr && v != mx.second) {\n            dfs(v, u, 0);\n        }\n    }\n\n    if(mx.second != -1) {\n        dfs(mx.second, u, 1);\n    }\n\n    for(int v: G[u]) {\n        if(v != pr && v != mx.second) {\n            add(v, u);\n        }\n    }\n\n    add_vertex(u);\n\n    if(keep) {\n        return;\n    }\n    clear(u, pr);\n}\n\nvoid solve() {\n    pre_dfs(1, -1);\n    dfs(1, -1, 1);\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/tree/hld.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\ntemplate<class T, class T2> inline int chkmax(T &x, const T2 &y) { return x < y ? x = y, 1 : 0; }\ntemplate<class T, class T2> inline int chkmin(T &x, const T2 &y) { return x > y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\n\nint n;\nvector<int> adj[MAXN];\n\nvoid read()\n{\n\tcin >> n;\n\tfor(int i = 0; i < n - 1; i++)\n\t{\n\t\tint u, v;\n\t\tcin >> u >> v;\n\t\tadj[u].push_back(v);\n\t\tadj[v].push_back(u);\n\t}\n}\n\nint tr_sz[MAXN];\n\nint pre_dfs(int u, int pr)\n{\n\ttr_sz[u] = 1;\n\tfor(int v: adj[u])\n\t\tif(v != pr)\n\t\t\ttr_sz[u] += pre_dfs(v, u);\n\n\treturn tr_sz[u];\n}\n\nint head[MAXN], par[MAXN][20], st[MAXN], en[MAXN], dfs_time;\n\nvoid decompose(int u, int pr, int head)\n{\n\t::head[u] = head;\n\tst[u] = ++dfs_time;\n\n\tpar[u][0] = pr;\n\tfor(int i = 1; i < 20; i++)\n\t\tpar[u][i] = par[par[u][i - 1]][i - 1];\n\n\tint mx_sz = -1, f_c = -1;\n\tfor(int v: adj[u])\n\t\tif(v != pr)\n\t\t\tif(chkmax(mx_sz, tr_sz[v]))\n\t\t\t\tf_c = v;\n\n\tif(f_c != -1)\n\t\tdecompose(f_c, u, head);\n\n\tfor(int v: adj[u])\n\t\tif(v != pr && v != f_c)\n\t\t\tdecompose(v, u, v);\n\n\ten[u] = dfs_time;\n}\n\ninline int upper(int u, int v) { return st[u] <= st[v] && en[v] <= en[u];  }\n\nint lca(int u, int v)\n{\n\tif(upper(u, v)) return u;\n\tif(upper(v, u)) return v;\n\n\tfor(int i = 19; i >= 0; i--)\n\t\tif(!upper(par[u][i], v))\n\t\t\tu = par[u][i];\n\n\treturn par[u][0];\n}\n\nvoid hld_precompute(int root)\n{\n\tpre_dfs(root, root);\n\tdecompose(1, 1, 1);\n}\n\nvector<pair<int, int> > get_path_up(int u, int anc)\n{\n\tvector<pair<int, int> > ret;\n\twhile(st[anc] < st[u])\n\t{\n\t\tret.push_back({max(st[anc] + 1, st[head[u]]), st[u]});\n\t\tu = par[head[u]][0];\n\t}\n\n\treturn ret;\n}\n\nvector<pair<int, int> > get_path(int u, int v)\n{\n\tint l = lca(u, v);\n\tvector<pair<int, int> > ret = get_path_up(u, l);\n\t\n\t// if we consider vertices, not edges\n\t// ret.push_back({st[l], st[l]});\n\n\tvector<pair<int, int> > oth = get_path_up(v, l);\n\treverse(oth.begin(), oth.end());\n\t\n\t// if the path is directed\n\t// for(auto &it: oth) swap(it.first, it.second);\n\t\n\tfor(auto it: oth) ret.push_back(it);\n\n\treturn ret;\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/tree/lca-seg3.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int MAXLOG = 20;\n\nint n, w[MAXN];\nvector<int> adj[MAXN];\n\nvoid read()\n{\n\tcin >> n;\n\tfor(int i = 1; i <= n; i++)\n\t\tcin >> w[i];\n\n\tfor(int i = 1; i <= n - 1; i++)\n\t{\n\t\tint u, v;\n\t\tcin >> u >> v;\n\t\tadj[u].push_back(v);\n\t\tadj[v].push_back(u);\n\t}\n}\n\nint st[MAXN], en[MAXN], dfs_time, par[MAXN][MAXLOG], par_mn[MAXN][MAXLOG];\n\nvoid pre_dfs(int u, int pr)\n{\n\tpar[u][0] = pr;\n\tpar_mn[u][0] = w[u];\n\tst[u] = ++dfs_time;\n\n\tfor(int i = 1; i < MAXLOG; i++)\n\t{\n\t\tpar[u][i] = par[par[u][i - 1]][i - 1];\n\t\tpar_mn[u][i] = min(par_mn[u][i - 1], par_mn[par_mn[u][i - 1]][i - 1]);\n\t}\n\n\tfor(int v: adj[u])\n\t\tif(v != pr)\n\t\t\tpre_dfs(v, u);\n\n\ten[u] = dfs_time;\n}\n\ninline bool upper(int u, int v) { return st[u] <= st[v] && en[v] <= en[u];  }\n\nint lca(int u, int v)\n{\n\tif(upper(u, v)) return u;\n\tif(upper(v, u)) return v;\n\n\tfor(int l = MAXLOG - 1; l >= 0; l--)\n\t\tif(!upper(par[u][l], v))\n\t\t\tu = par[u][l];\n\n\treturn par[u][0];\n}\n\nint get_path_up(int u, int anc)\n{\n\tif(upper(u, anc)) return (int)1e9;\n\n\tint ans = INT_MAX;\n\tfor(int l = MAXLOG - 1; l >= 0; l--)\n\t\tif(!upper(par[u][l], anc))\n\t\t{\n\t\t\tans = min(ans, par_mn[u][l]);\n\t\t\tu = par[u][l];\n\t\t}\n\t\n\treturn ans;\n}\n\nint get_path(int u, int v)\n{\n\tint anc = lca(u, v), ans = w[anc];\n\tans = min(get_path_up(u, anc), get_path_up(v, anc));\n\treturn ans;\n}\n\nvoid lca_precompute(int root)\n{\n\tdfs_time = 0;\n\tpre_dfs(root, root);\n}\n\nvoid solve()\n{\n\tlca_precompute(1);\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "old_impl/tree/link_cut_tree.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nrandom_device rd;\nmt19937_64 mt(rd());\n\nstruct node {\n    int sz, prior, id, rev;\n    node *par, *pp, *l, *r;\n    node() {\n        id = 0;\n        sz = 0;\n        rev = 0;\n        prior = 0;\n        par = nullptr;\n        l = nullptr;\n        r = nullptr;\n        pp = nullptr;\n    }\n    node(int v) {\n        id = v;\n        sz = 1;\n        rev = 0;\n        prior = mt();\n        l = nullptr;\n        r = nullptr;\n        par = nullptr;\n        pp = nullptr;\n    }\n};\n\nint size(node *v) { return v ? v->sz : 0; }\n\nvoid push(node *&t) {\n    if(!t) {\n        return;\n    }\n    if(t->rev) {\n        swap(t->l, t->r);\n        if(t->l) {\n            t->l->rev ^= 1;\n        }\n        if(t->r) {\n            t->r->rev ^= 1;\n        }\n        t->rev = 0;\n    }\n}\n\nvoid pull(node *&v) {\n    if(!v) {\n        return;\n    }\n\n    push(v->l);\n    push(v->r);\n\n    v->par = nullptr;\n    v->sz = size(v->l) + size(v->r) + 1;\n\n    if(v->l) {\n        v->l->par = v;\n    }\n    if(v->r) {\n        v->r->par = v;\n    }\n\n    if(v->l && v->l->pp) {\n        v->pp = v->l->pp, v->l->pp = nullptr;\n    }\n    if(v->r && v->r->pp) {\n        v->pp = v->r->pp, v->r->pp = nullptr;\n    }\n}\n\nvoid merge(node *&t, node *l, node *r) {\n    push(l), push(r);\n    if(!l) {\n        t = r;\n        return;\n    }\n    if(!r) {\n        t = l;\n        return;\n    }\n\n    if(l->prior > r->prior) {\n        merge(l->r, l->r, r), t = l;\n    } else {\n        merge(r->l, l, r->l), t = r;\n    }\n\n    pull(t);\n}\n\nvoid split(node *t, node *&l, node *&r, int k, int add = 0) {\n    push(t);\n    if(!t) {\n        l = nullptr;\n        r = nullptr;\n        return;\n    }\n\n    int idx = add + size(t->l);\n    if(idx <= k) {\n        split(t->r, t->r, r, k, idx + 1), l = t;\n    } else {\n        split(t->l, l, t->l, k, add), r = t;\n    }\n\n    pull(t);\n}\n\nnode *get_root(node *t) {\n    if(!t) {\n        return nullptr;\n    }\n    while(t->par) {\n        t = t->par;\n    }\n    return t;\n}\n\nnode *remove_right(node *t) {\n    node *rt = t;\n\n    int pos = size(rt->l);\n    if(rt->rev) {\n        pos = size(rt) - pos - 1;\n    }\n    while(rt->par) {\n        if(rt->par->r == rt) {\n            pos += size(rt->par->l) + 1;\n        }\n        if(rt->par->rev) {\n            pos = size(rt->par) - pos - 1;\n        }\n        rt = rt->par;\n    }\n\n    node *l, *r, *pp = rt->pp;\n    rt->pp = nullptr;\n    split(rt, l, r, pos);\n\n    l->pp = pp;\n    if(r) {\n        r->pp = t;\n    }\n\n    return l;\n}\n\nnode *remove_left(node *t) {\n    node *rt = t;\n\n    int pos = size(rt->l);\n    if(rt->rev) {\n        pos = size(rt) - pos - 1;\n    }\n    while(rt->par) {\n        if(rt->par->r == rt) {\n            pos += size(rt->par->l) + 1;\n        }\n        if(rt->par->rev) {\n            pos = size(rt->par) - pos - 1;\n        }\n        rt = rt->par;\n    }\n\n    node *l, *r, *pp = rt->pp;\n    rt->pp = nullptr;\n    split(rt, l, r, pos - 1);\n\n    l->pp = pp;\n    return r;\n}\n\nnode *merge_trees(node *u, node *t) {\n    u = get_root(u);\n    t = get_root(t);\n    t->pp = nullptr;\n    merge(u, u, t);\n    return u;\n}\n\n\nstruct link_cut_tree {\n    node *ver[MAXN];\n\n    node *access(node *t) {\n        t = remove_right(t);\n        while(t->pp) {\n            node *u = t->pp;\n            u = remove_right(u);\n            t = merge_trees(u, t);\n        }\n\n        return t;\n    }\n\n    node *find_root(node *u) {\n        u = access(u);\n        push(u);\n        while(u->l) {\n            u = u->l, push(u);\n        }\n        access(u);\n        return u;\n    }\n\n    void make_root(node *u) {\n        u = access(u);\n        u->rev ^= 1;\n        push(u);\n    }\n\n    void link(node *u, node *w) {\n        make_root(u);\n        access(w);\n        merge_trees(w, u);\n    }\n\n    void cut(node *p) {\n        access(p);\n        remove_left(p);\n    }\n\n    int depth(node *u) {\n        u = access(u);\n        return size(u);\n    }\n\n    node *lca(node *u, node *v) {\n        if(u == v) {\n            return u;\n        }\n        if(depth(u) > depth(v)) {\n            swap(u, v);\n        }\n\n        access(v);\n        access(u);\n\n        return get_root(v)->pp;\n    }\n\n    /// normal functions\n    void init(int c) {\n        for(int i = 0; i <= c; i++) {\n            ver[i] = new node(i);\n        }\n    }\n    inline int lca(int u, int v) { return lca(ver[u], ver[v])->id; }\n    inline int root(int u) { return find_root(ver[u])->id; }\n    inline void link(int u, int v) { link(ver[u], ver[v]); }\n    inline void make_root(int u) { make_root(ver[u]); }\n    inline int depth(int u) { return depth(ver[u]); }\n    inline void cut(int u) { cut(ver[u]); }\n};\n\nint n, m;\n\nvoid read() { cin >> n >> m; }\n\nlink_cut_tree lct;\n\nvoid solve() {\n    lct.init(n);\n\n    while(m--) {\n        string type;\n        cin >> type;\n\n        if(type == \"add\") {\n            int u, w;\n            cin >> u >> w;\n            lct.link(u, w);\n        } else if(type == \"conn\") {\n            int u, v;\n            cin >> u >> v;\n            cout << (lct.root(u) == lct.root(v) ? \"YES\" : \"NO\") << endl;\n        } else if(type == \"rem\") {\n            int u, v;\n            cin >> u >> v;\n            if(lct.depth(u) > lct.depth(v)) {\n                swap(u, v);\n            }\n            lct.cut(v);\n        }\n    }\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "old_impl/tree/virtual_tree.cpp",
    "content": "#include <bits/stdc++.h>\n\nusing namespace std;\nconst int MAXLOG = 20;\n\nint n;\nvector<vector<int>> adj;\n\nvoid read() {\n    cin >> n;\n    adj.assign(n + 1, {});\n    for(int i = 0; i < n - 1; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n}\n\nvector<int> in_time, out_time;\nvector<vector<int>> par_up;\n\nvoid dfs_lca(int u, int pr, int &dfs_time) {\n    in_time[u] = ++dfs_time;\n\n    par_up[u].resize(MAXLOG);\n    par_up[u][0] = pr;\n    for(int i = 1; i < MAXLOG; i++) {\n        par_up[u][i] = par_up[par_up[u][i - 1]][i - 1];\n    }\n\n    for(int v: adj[u]) {\n        if(v != pr) {\n            dfs_lca(v, u, dfs_time);\n        }\n    }\n\n    out_time[u] = dfs_time;\n}\n\ninline bool upper(int u, int v) {\n    return in_time[u] <= in_time[v] && out_time[v] <= out_time[u];\n}\n\nint lca(int u, int v) {\n    if(upper(u, v)) {\n        return u;\n    }\n    if(upper(v, u)) {\n        return v;\n    }\n\n    int a = u;\n    for(int i = MAXLOG - 1; i >= 0; i--) {\n        if(!upper(par_up[a][i], v)) {\n            a = par_up[a][i];\n        }\n    }\n\n    return par_up[a][0];\n}\n\nvoid lca_precompute(int root) {\n    int dfs_time = 0;\n    in_time.resize(n + 1);\n    out_time.resize(n + 1);\n    par_up.resize(n + 1);\n    dfs_lca(root, root, dfs_time);\n}\n\nvector<vector<int>> vg;\n\nint build_tree(vector<int> vec) {\n    if(vec.empty()) {\n        return -1;\n    }\n\n    function<bool(int, int)> cmp = [&](int u, int v) {\n        return in_time[u] < in_time[v];\n    };\n    function<void(stack<int> &)> propagate_stack = [&](stack<int> &mstack) {\n        int prev_top = mstack.top();\n        mstack.pop();\n        vg[mstack.top()].push_back(prev_top);\n    };\n\n    sort(vec.begin(), vec.end(), cmp);\n    vec.erase(unique(vec.begin(), vec.end()), vec.end());\n\n    for(int i = (int)vec.size() - 1; i > 0; i--) {\n        vec.push_back(lca(vec[i - 1], vec[i]));\n    }\n\n    sort(vec.begin(), vec.end(), cmp);\n    vec.erase(unique(vec.begin(), vec.end()), vec.end());\n\n    for(int vertex: vec) {\n        vg[vertex].clear();\n    }\n\n    stack<int> mstack;\n    mstack.push(vec[0]);\n\n    for(int i = 1; i < (int)vec.size(); i++) {\n        while(!upper(mstack.top(), vec[i])) {\n            propagate_stack(mstack);\n        }\n\n        mstack.push(vec[i]);\n    }\n\n    while(mstack.size() > 1) {\n        propagate_stack(mstack);\n    }\n\n    return mstack.top();\n}\n\nvoid solve() {\n    lca_precompute(1);\n    vg.assign(n + 1, {});\n\n    int q;\n    cin >> q;\n    for(int i = 0; i < q; i++) {\n        int x, xx;\n        cin >> x;\n        vector<int> vec;\n\n        for(int i = 0; i < x; i++) {\n            cin >> xx;\n            vec.push_back(xx);\n        }\n\n        int root = build_tree(vec);\n    }\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(NULL);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "other/bits/bit_trie.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, int num_bits>\nclass BitTrie {\n  public:\n    struct node {\n        array<int, 2> to;\n        int cnt;\n\n        node() {\n            to = {-1, -1};\n            cnt = 0;\n        }\n    };\n\n    vector<node> trie;\n\n    void clear() { trie = {node()}; }\n\n    BitTrie() { clear(); }\n\n    void add(T x, int cnt) {\n        int u = 0;\n        trie[0].cnt += cnt;\n        for(int i = num_bits - 1; i >= 0; i--) {\n            int bit = (x >> i) & 1;\n            if(trie[u].to[bit] == -1) {\n                trie[u].to[bit] = (int)trie.size();\n                trie.push_back(node());\n            }\n            u = trie[u].to[bit];\n            trie[u].cnt += cnt;\n        }\n    }\n\n    T max_xor(T x) {\n        int u = 0;\n        T res = 0;\n        for(int i = num_bits - 1; i >= 0; i--) {\n            int bit = (x >> i) & 1;\n            if(trie[u].to[bit ^ 1] != -1 && trie[trie[u].to[bit ^ 1]].cnt > 0) {\n                res |= (T)1 << i;\n                u = trie[u].to[bit ^ 1];\n            } else {\n                u = trie[u].to[bit];\n            }\n        }\n\n        return res;\n    }\n};\n"
  },
  {
    "path": "other/bits/xor_basis.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T, int num_bits>\nclass XorBasis {\n  public:\n    int sz;\n    vector<T*> base;\n\n    void clear() {\n        sz = 0;\n        base.assign(num_bits, nullptr);\n    }\n    XorBasis() { clear(); }\n\n    void add(T val) {\n        for(int i = num_bits - 1; i >= 0; i--) {\n            if(get_bit(val, i)) {\n                if(!base[i]) {\n                    base[i] = new T(val);\n                    sz++;\n                    return;\n                } else {\n                    val = xor_op(val, *base[i]);\n                }\n            }\n        }\n    }\n\n    inline int size() { return sz; }\n\n    T max_xor() {\n        T res = T();\n        for(int i = num_bits - 1; i >= 0; i--) {\n            if(!get_bit(res, i) && base[i]) {\n                res = xor_op(res, *base[i]);\n            }\n        }\n\n        return res;\n    }\n\n    bool can_create(T val) {\n        for(int i = num_bits - 1; i >= 0; i--) {\n            if(get_bit(val, i) && base[i]) {\n                val = xor_op(val, *base[i]);\n            }\n        }\n        return is_zero(val);\n    }\n\n    vector<T> get_basis() {\n        vector<T> res;\n        for(int i = 0; i < num_bits; i++) {\n            if(!base[i]) {\n                res.push_back(*base[i]);\n            }\n        }\n        return res;\n    }\n\n    XorBasis<T, num_bits> merge(const XorBasis<T, num_bits>& other) {\n        if(sz < other.size()) {\n            return other.merge(*this);\n        }\n\n        XorBasis<T, num_bits> res = *this;\n        for(auto x: other.base) {\n            if(x) {\n                res.add(*x);\n            }\n        }\n        return res;\n    }\n\n  private:\n    // Helper functions for different types\n\n    // For integral types\n    template<typename U = T>\n    typename enable_if<is_integral<U>::value, bool>::type get_bit(\n        const T& val, int pos\n    ) const {\n        return (val >> pos) & 1;\n    }\n\n    template<typename U = T>\n    typename enable_if<is_integral<U>::value, bool>::type is_zero(const T& val\n    ) const {\n        return val == 0;\n    }\n\n    template<typename U = T>\n    typename enable_if<is_integral<U>::value, T>::type xor_op(\n        const T& a, const T& b\n    ) const {\n        return a ^ b;\n    }\n\n    // For bitset\n    template<size_t N, typename U = T>\n    typename enable_if<is_same<U, bitset<N>>::value, bool>::type get_bit(\n        const bitset<N>& val, int pos\n    ) const {\n        return val[pos];\n    }\n\n    template<size_t N, typename U = T>\n    typename enable_if<is_same<U, bitset<N>>::value, bool>::type is_zero(\n        const bitset<N>& val\n    ) const {\n        return val.none();\n    }\n\n    template<size_t N, typename U = T>\n    typename enable_if<is_same<U, bitset<N>>::value, bitset<N>>::type xor_op(\n        const bitset<N>& a, const bitset<N>& b\n    ) const {\n        return a ^ b;\n    }\n};\n"
  },
  {
    "path": "other/dp_optimizations/LiChao_dynamic.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int64_t inf = (int64_t)1e17 + 42;\n\nstruct LiChao_max\n{\n\tstruct line\n\t{\n\t\tint a, b;\n\t\tline() { a = 0; b = 0; }\n\t\tline(int _a, int _b) { a = _a; b = _b; }\n\t\tint64_t eval(int x) { return a * 1ll * x + (int64_t)b; }\n\t};\n\n\tstruct node\n\t{\n\t\tnode *l, *r; line f;\n\n\t\tnode() { f = line(); l = nullptr; r = nullptr; }\n\t\tnode(int a, int b) { f = line(a, b); l = nullptr; r = nullptr; }\n\t\tnode(line v) { f = v; l = nullptr; r = nullptr; }\n\t};\n\n\ttypedef node* pnode;\n\n\tpnode root; int sz;\n\tvoid init(int _sz) { sz = _sz + 1; root = nullptr; }\n\n\tvoid add_line(int a, int b) { line v = line(a, b); insert(v, -sz, sz, root); }\n\tint64_t query(int x) { return query(x, -sz, sz, root); }\n\n\tvoid insert(line &v, int l, int r, pnode &nd)\n\t{\n\t\tif(!nd) { nd = new node(v); return; }\n\n\t\tint64_t trl = nd->f.eval(l), trr = nd->f.eval(r);\n\t\tint64_t vl = v.eval(l), vr = v.eval(r);\n\n\t\tif(trl >= vl && trr >= vr) return;\n\t\tif(trl < vl && trr < vr) { nd->f = v; return; }\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(trl < vl) swap(nd->f, v);\n\t\tif(nd->f.eval(mid) > v.eval(mid)) insert(v, mid + 1, r, nd->r);\n\t\telse swap(nd->f, v), insert(v, l, mid, nd->l);\n\t}\n\n\tint64_t query(int x, int l, int r, pnode &nd)\n\t{\n\t\tif(!nd) return -inf;\n\t\tif(l == r) return nd->f.eval(x);\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(mid >= x) return max(nd->f.eval(x), query(x, l, mid, nd->l));\n\t\treturn max(nd->f.eval(x), query(x, mid + 1, r, nd->r));\n\t}\n};\n\nstruct LiChao_min\n{\n\tstruct line\n\t{\n\t\tint a, b;\n\t\tline() { a = 0; b = 0; }\n\t\tline(int _a, int _b) { a = _a; b = _b; }\n\t\tint64_t eval(int x) { return a * 1ll * x + (int64_t)b; }\n\t};\n\n\tstruct node\n\t{\n\t\tnode *l, *r; line f;\n\n\t\tnode() { f = line(); l = nullptr; r = nullptr; }\n\t\tnode(int a, int b) { f = line(a, b); l = nullptr; r = nullptr; }\n\t\tnode(line v) { f = v; l = nullptr; r = nullptr; }\n\t};\n\n\ttypedef node* pnode;\n\n\tpnode root; int sz;\n\tvoid init(int _sz) { sz = _sz + 1; root = nullptr; }\n\n\tvoid add_line(int a, int b) { line v = line(a, b); insert(v, -sz, sz, root); }\n\tint64_t query(int x) { return query(x, -sz, sz, root); }\n\n\tvoid insert(line &v, int l, int r, pnode &nd)\n\t{\n\t\tif(!nd) { nd = new node(v); return; }\n\n\t\tint64_t trl = nd->f.eval(l), trr = nd->f.eval(r);\n\t\tint64_t vl = v.eval(l), vr = v.eval(r);\n\n\t\tif(trl <= vl && trr <= vr) return;\n\t\tif(trl > vl && trr > vr) { nd->f = v; return; }\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(trl > vl) swap(nd->f, v);\n\t\tif(nd->f.eval(mid) < v.eval(mid)) insert(v, mid + 1, r, nd->r);\n\t\telse swap(nd->f, v), insert(v, l, mid, nd->l);\n\t}\n\n\tint64_t query(int x, int l, int r, pnode &nd)\n\t{\n\t\tif(!nd) return inf;\n\t\tif(l == r) return nd->f.eval(x);\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(mid >= x) return min(nd->f.eval(x), query(x, l, mid, nd->l));\n\t\treturn min(nd->f.eval(x), query(x, mid + 1, r, nd->r));\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "other/dp_optimizations/LiChao_parabolic.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int inf = (int)1e9 + 42;\n\ntemplate<class T>\nstruct LiChao_parabolic_min {\n\tstruct Parabol {\n\t\tT a, b, c;\n\t\tParabol() {a = 0; b = 0; c = inf;}\n\t\tParabol(T a, T b, T c) : a(a), b(b), c(c) {}\n\t\tParabol(const Parabol& rhs) {\n\t\t\ta = rhs.a;\n\t\t\tb = rhs.b;\n\t\t\tc = rhs.c;\n\t\t}\n\t\tT query(T x) {\n\t\t\treturn a * x * x + b * x + c;\n\t\t}\n\t};\n\tstruct Node {\n\t\tParabol prb;\n\t\tNode *l, *r;\n\t\tNode() : l(0), r(0) {}\n\t\tT query(T x) {\n\t\t\treturn prb.query(x);\n\t\t}\n\t};\n\n\tNode* rt;\n\tT offset;\n\tvector<Parabol> mem;\n\n\tLiChao_parabolic_min() : rt(0), offset(0) {}\n\n\tNode* upd(Node* p, int l, int r, int L, int R, Parabol prb) {\n\t\tint M = (L + R) >> 1;\n\t\tif (l > R || r < L) return p;\n\t\tif (!p) p = new Node();\n\t\tif (l <= L && r >= R) {\n\t\t\tif (prb.query(L) >= p->query(L) && prb.query(R) >= p->query(R)) {\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\tif (prb.query(L) <= p->query(L) && prb.query(R) <= p->query(R)) {\n\t\t\t\tp->prb = prb;\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\tif (prb.query(L) >= p->query(L) && prb.query(M) >= p->query(M)) {\n\t\t\t\tp->r = upd(p->r, l, r, M + 1, R, prb);\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\tif (prb.query(L) <= p->query(L) && prb.query(M) <= p->query(M)) {\n\t\t\t\tp->r = upd(p->r, l, r, M + 1, R, p->prb);\n\t\t\t\tp->prb = prb;\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\tif (prb.query(M + 1) >= p->query(M + 1) && prb.query(R) >= p->query(R)) {\n\t\t\t\tp->l = upd(p->l, l, r, L, M, prb);\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\tif (prb.query(M + 1) <= p->query(M + 1) && prb.query(R) <= p->query(R)) {\n\t\t\t\tp->l = upd(p->l, l, r, L, M, p->prb);\n\t\t\t\tp->prb = prb;\n\t\t\t\treturn p;\n\t\t\t}\n\t\t\treturn p;\n\t\t}\n\t\telse if (L < R) {\n\t\t\tp->l = upd(p->l, l, r, L, (L + R) >> 1, prb);\n\t\t\tp->r = upd(p->r, l, r, ((L + R) >> 1) + 1, R, prb);\n\t\t}\n\t}\n\tT query(Node* p, int i, int L, int R) {\n\t\tif (!p) return inf;\n\t\tif (i < L || i > R) return inf;\n\t\tT res = inf;\n\t\tres = min(res, p->query(i));\n\t\tif (L < R) {\n\t\t\tres = min(res, query(p->l, i, L, (L + R) >> 1));\n\t\t\tres = min(res, query(p->r, i, ((L + R) >> 1) + 1, R));\n\t\t}\n\t\treturn res;\n\t}\n\tvoid upd(T a, T b, T c) {\n\t\tmem.push_back(Parabol(a, b, c));\n\t\trt = upd(rt, 0, 100005, 0, 100005, Parabol(a, b, c));\n\t}\n\tT query(int i) {\n\t\treturn query(rt, i, 0, 100005);\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "other/dp_optimizations/LiChao_segment_tree_offline.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst double inf = (double)1e17 + 42;\n\nstruct LiChao_max\n{\n\tstruct line\n\t{\n\t\tdouble a, b;\n\t\tline() { a = 0; b = 0; }\n\t\tline(double _a, double _b) { a = _a; b = _b; }\n\t\tdouble eval(int x) { return a * x + b; }\n\t};\n\n\tline tr[4 * MAXN];\n\tbool vis[4 * MAXN];\n\tint value[MAXN];\n\tint sz;\n\n\tvoid init(int l, int r, int idx)\n\t{\n\t\tif(r < l) return;\n\n\t\tvis[idx] = 0;\n\t\tif(l == r) return;\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\t}\n\n\tvoid init(vector<int> Q)\n\t{\n\t\tsort(Q.begin(), Q.end());\n\t\tQ.erase(unique(Q.begin(), Q.end()), Q.end());\n\n\t\tsz = Q.size();\n\t\tfor(int i = 0; i < (int)Q.size(); i++)\n\t\t\tvalue[i + 1] = Q[i];\n\n\t\tinit(1, sz, 0);\n\t}\n\n\tvoid add_line(double a, double b) { line v = line(a, b); insert(v, 1, sz, 0); }\n\tdouble query(int x) { return query(x, 1, sz, 0); }\n\n\tvoid insert(line &v, int l, int r, int idx)\n\t{\n\t\tif(!vis[idx]) { tr[idx] = v; vis[idx] = true; return; }\n\n\t\tdouble trl = tr[idx].eval(value[l]), trr = tr[idx].eval(value[r]), vl = v.eval(value[l]), vr = v.eval(value[r]);\n\n\t\tif(trl >= vl && trr >= vr) return;\n\t\tif(trl < vl && trr < vr) { tr[idx] = v; return; }\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(trl < vl) swap(tr[idx], v);\n\t\tif(tr[idx].eval(value[mid]) > v.eval(value[mid])) insert(v, mid + 1, r, 2 * idx + 2);\n\t\telse swap(tr[idx], v), insert(v, l, mid, 2 * idx + 1);\n\t}\n\n\tdouble query(int x, int l, int r, int idx)\n\t{\n\t\tif(!vis[idx]) return -inf;\n\t\tif(l == r) return tr[idx].eval(x);\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(value[mid] >= x) return max(tr[idx].eval(x), query(x, l, mid, 2 * idx + 1));\n\t\treturn max(tr[idx].eval(x), query(x, mid + 1, r, 2 * idx + 2));\n\t}\n};\n\nstruct LiChao_min\n{\n\tstruct line\n\t{\n\t\tdouble a, b;\n\t\tline() { a = 0; b = 0; }\n\t\tline(double _a, double _b) { a = _a; b = _b; }\n\t\tdouble eval(int x) { return a * x + b; }\n\t};\n\n\tline tr[4 * MAXN];\n\tbool vis[4 * MAXN];\n\tint value[MAXN];\n\tint sz;\n\n\tvoid init(int l, int r, int idx)\n\t{\n\t\tif(r < l) return;\n\n\t\tvis[idx] = 0;\n\t\tif(l == r) return;\n\n\t\tint mid = (l + r) >> 1;\n\t\tinit(l, mid, 2 * idx + 1);\n\t\tinit(mid + 1, r, 2 * idx + 2);\n\t}\n\n\tvoid init(vector<int> Q)\n\t{\n\t\tsort(Q.begin(), Q.end());\n\t\tQ.erase(unique(Q.begin(), Q.end()), Q.end());\n\n\t\tsz = Q.size();\n\t\tfor(int i = 0; i < (int)Q.size(); i++)\n\t\t\tvalue[i + 1] = Q[i];\n\n\t\tinit(1, sz, 0);\n\t}\n\n\tvoid add_line(double a, double b) { line v = line(a, b); insert(v, 1, sz, 0); }\n\tdouble query(int x) { return query(x, 1, sz, 0); }\n\n\tvoid insert(line &v, int l, int r, int idx)\n\t{\n\t\tif(!vis[idx]) { tr[idx] = v; vis[idx] = true; return; }\n\n\t\tdouble trl = tr[idx].eval(value[l]), trr = tr[idx].eval(value[r]), vl = v.eval(value[l]), vr = v.eval(value[r]);\n\n\t\tif(trl <= vl && trr <= vr) return;\n\t\tif(trl > vl && trr > vr) { tr[idx] = v; return; }\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(trl > vl) swap(tr[idx], v);\n\t\tif(tr[idx].eval(value[mid]) < v.eval(value[mid])) insert(v, mid + 1, r, 2 * idx + 2);\n\t\telse swap(tr[idx], v), insert(v, l, mid, 2 * idx + 1);\n\t}\n\n\tdouble query(int x, int l, int r, int idx)\n\t{\n\t\tif(!vis[idx]) return inf;\n\t\tif(l == r) return tr[idx].eval(x);\n\n\t\tint mid = (l + r) >> 1;\n\t\tif(value[mid] >= x) return min(tr[idx].eval(x), query(x, l, mid, 2 * idx + 1));\n\t\treturn min(tr[idx].eval(x), query(x, mid + 1, r, 2 * idx + 2));\n\t}\n};\n\nvoid read()\n{\n\n}\n\nvoid solve()\n{\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "other/dp_optimizations/convex_hull_trick_max.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int64_t inf = (int64_t)1e18 + 42;\n\nstruct convex_hull_trick_max\n{\n\tstruct line\n\t{\n\t\tint64_t m, b;\n\t\tbool is_query;\n\t\tdouble line_x;\n\n\t\tline() {m = 0; b = 0; line_x = 0; is_query = 0; }\n\t\tline(int64_t _m, int64_t _b) {m = _m; b = _b; line_x = 0; is_query = 0; }\n\n\t\tbool operator<(const line &l2) const\n\t\t{\n\t\t\tif(!is_query && !l2.is_query) return m < l2.m;\n\t\t\telse return line_x < l2.line_x;\n\t\t}\n\n\t\tint64_t value_at(int64_t x) const { return m * x + b; }\n\t};\n\n\tbool parallel(const line &l1, const line &l2) { return l1.m == l2.m; }\n\n\tdouble intersect_x(const line &l1, const line &l2)\n\t{\n\t\tif(parallel(l1, l2)) return (double)inf;\n\t\treturn (double)(l1.b - l2.b) / (double)(l2.m - l1.m);\n\t}\n\n\tset<line> hull;\n\tvoid clear() { hull.clear(); }\n\tvoid init() { clear(); }\n\n\tbool has_next(set<line>::iterator it) { return it != hull.end() && next(it) != hull.end(); }\n\tbool has_prev(set<line>::iterator it) { return it != hull.end() && it != hull.begin(); }\n\n\tbool irrelevant(const line &l1, const line &l2, const line &l3) { return intersect_x(l1, l3) <= intersect_x(l1, l2); }\n\tbool irrelevant(set<line>::iterator it) { return has_prev(it) && has_next(it) && irrelevant(*prev(it), *it, *next(it)); }\n\n\tset<line>::iterator update_border(set<line>::iterator it)\n\t{\n\t\tline tmp(*it);\n\n\t\tdouble val;\n\t\tif(has_next(it)) val = intersect_x(*it, *next(it));\n\t\telse val = inf;\n\n\t\tit = hull.erase(it);\n\t\ttmp.line_x = val;\n\t\tit = hull.insert(it, tmp);\n\n\t\treturn it;\n\t}\n\n\tvoid add_line(int64_t m, int64_t b)\n\t{\n\t\tline curr_line = line(m, b);\n\t\tset<line>::iterator it = hull.lower_bound(curr_line);\n\n\t\tif(it != hull.end() && it->m == m)\n\t\t{\n\t\t\tif(it->b < b) it = hull.erase(it);\n\t\t\telse return;\n\t\t}\n\n\t\tit = hull.insert(it, curr_line);\n\t\tif(irrelevant(it))\n\t\t{\n\t\t\thull.erase(it);\n\t\t\treturn;\n\t\t}\n\n\t\twhile(has_prev(it) && irrelevant(prev(it))) hull.erase(prev(it));\n\t\twhile(has_next(it) && irrelevant(next(it))) hull.erase(next(it));\n\n\t\tit = update_border(it);\n\t\tif(has_prev(it)) update_border(prev(it));\n\t\tif(has_next(it)) update_border(next(it));\n\t}\n\n\tint64_t query(int64_t x)\n\t{\n\t\tline to_find;\n\t\tto_find.line_x = x;\n\t\tto_find.is_query = 1;\n\n\t\tset<line>::iterator best_line = hull.lower_bound(to_find);\n\t\tif(best_line == hull.end())\n\t\t\treturn inf;\n\n\t\treturn best_line->value_at(x);\n\t}\n};\n\nvoid read()\n{\n\n}\n\nconvex_hull_trick_max cht;\n\nvoid solve()\n{\n\tcht.init();\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "other/dp_optimizations/convex_hull_trick_min.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\nconst int64_t inf = (int64_t)1e18 + 42;\n\nstruct convex_hull_trick_min\n{\n\tstruct line\n\t{\n\t\tint64_t m, b;\n\t\tbool is_query;\n\t\tdouble line_x;\n\n\t\tline() {m = 0; b = 0; line_x = 0; is_query = 0; }\n\t\tline(int64_t _m, int64_t _b) {m = _m; b = _b; line_x = 0; is_query = 0; }\n\n\t\tbool operator<(const line &l2) const\n\t\t{\n\t\t\tif(!is_query && !l2.is_query) return m > l2.m;\n\t\t\telse return line_x < l2.line_x;\n\t\t}\n\n\t\tint64_t value_at(int64_t x) const { return m * x + b; }\n\t};\n\n\tbool parallel(const line &l1, const line &l2) { return l1.m == l2.m; }\n\n\tdouble intersect_x(const line &l1, const line &l2)\n\t{\n\t\tif(parallel(l1, l2)) return (double)inf;\n\t\treturn (double)(l1.b - l2.b) / (double)(l2.m - l1.m);\n\t}\n\n\tset<line> hull;\n\tvoid clear() { hull.clear(); }\n\tvoid init() { clear(); }\n\n\tbool has_next(set<line>::iterator it) { return it != hull.end() && next(it) != hull.end(); }\n\tbool has_prev(set<line>::iterator it) { return it != hull.end() && it != hull.begin(); }\n\n\tbool irrelevant(const line &l1, const line &l2, const line &l3) { return intersect_x(l1, l3) <= intersect_x(l1, l2); }\n\tbool irrelevant(set<line>::iterator it) { return has_prev(it) && has_next(it) && irrelevant(*prev(it), *it, *next(it)); }\n\n\tset<line>::iterator update_border(set<line>::iterator it)\n\t{\n\t\tline tmp(*it);\n\n\t\tdouble val;\n\t\tif(has_next(it)) val = intersect_x(*it, *next(it));\n\t\telse val = inf;\n\n\t\tit = hull.erase(it);\n\t\ttmp.line_x = val;\n\t\tit = hull.insert(it, tmp);\n\n\t\treturn it;\n\t}\n\n\tvoid add_line(int64_t m, int64_t b)\n\t{\n\t\tline curr_line = line(m, b);\n\t\tset<line>::iterator it = hull.lower_bound(curr_line);\n\n\t\tif(it != hull.end() && it->m == m)\n\t\t{\n\t\t\tif(it->b > b) it = hull.erase(it);\n\t\t\telse return;\n\t\t}\n\n\t\tit = hull.insert(it, curr_line);\n\t\tif(irrelevant(it))\n\t\t{\n\t\t\thull.erase(it);\n\t\t\treturn;\n\t\t}\n\n\t\twhile(has_prev(it) && irrelevant(prev(it))) hull.erase(prev(it));\n\t\twhile(has_next(it) && irrelevant(next(it))) hull.erase(next(it));\n\n\t\tit = update_border(it);\n\t\tif(has_prev(it)) update_border(prev(it));\n\t\tif(has_next(it)) update_border(next(it));\n\t}\n\n\tint64_t query(int64_t x)\n\t{\n\t\tline to_find;\n\t\tto_find.line_x = x;\n\t\tto_find.is_query = 1;\n\n\t\tset<line>::iterator best_line = hull.lower_bound(to_find);\n\t\tif(best_line == hull.end())\n\t\t\treturn inf;\n\n\t\treturn best_line->value_at(x);\n\t}\n};\n\nvoid read()\n{\n\n}\n\nconvex_hull_trick_min cht;\n\nvoid solve()\n{\n\tcht.init();\n\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "other/dp_optimizations/divide_and_conquer_optimization.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (int)4e3 + 42;\nconst int inf = (int)1e9 + 42;\n\nvoid Read(int &x);\n\nint n, m;\n\nvoid read()\n{\n\n}\n\nint dp[MAXN][MAXN], cost[MAXN][MAXN];\n\nvoid rec(int l, int r, int opt_l, int opt_r, int k)\n{\n\tif(r < l) return;\n\n\tif(l == r)\n\t{\n\t\tdp[l][k] = inf;\n\t\tfor(int i = opt_l; i <= min(opt_r, l); i++)\n\t\t\tif(dp[l][k] > dp[i - 1][k - 1] + cost[i][l])\n\t\t\t\tdp[l][k] = dp[i - 1][k - 1] + cost[i][l];\n\n\t\treturn;\n\t}\n\n\tint mid = (l + r) >> 1, copt = opt_l;\n\n\tdp[mid][k] = inf;\n\tfor(int i = opt_l; i <= min(mid, opt_r); i++)\n\t\tif(dp[mid][k] > dp[i - 1][k - 1] + cost[i][mid])\n\t\t{\n\t\t\tdp[mid][k] = dp[i - 1][k - 1] + cost[i][mid];\n\t\t\tcopt = i;\n\t\t}\n\n\trec(l, mid - 1, opt_l, copt, k);\n\trec(mid + 1, r, copt, opt_r, k);\n}\n\nvoid solve()\n{\n\tfor(int i = 0; i <= n; i++) dp[i][0] = inf;\n\tfor(int i = 0; i <= m; i++) dp[0][i] = 0;\n\tfor(int k = 1; k <= m; k++)\n\t\trec(1, n, 1, n, k);\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n#define maxl 100000\nchar sir[maxl];\nint pos_ind = 0;\n\nvoid Next() { if(++pos_ind == maxl) fread(sir, 1, maxl, stdin), pos_ind = 0;  }\nvoid Read(int &x)\n{\n\t\tfor(; sir[pos_ind] < '0' || sir[pos_ind] > '9'; Next());\n\t\t\tfor(x = 0; sir[pos_ind] >= '0' && sir[pos_ind] <= '9'; Next())\n\t\t\t\t\t\tx = x * 10 + sir[pos_ind] - '0';\n\n}\n"
  },
  {
    "path": "other/dp_optimizations/slope_trick.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define SZ(x) ((int)x.size())\n#define ALL(V) V.begin(), V.end()\n#define lb lower_bound\n#define ub upper_bound\n#define pb push_back\n\nusing namespace std;\ntemplate<class T, class T1> int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; }\ntemplate<class T, class T1> int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\n\ntemplate<typename T>\nstruct slope_trick {\n\tT offset_l, offset_r, zero_height;\n\tmultiset<T> L;\n\tmultiset<T> R;\n\n\tslope_trick() {\n\t\toffset_l = 0;\n\t\toffset_r = 0;\n\t\tzero_height = 0;\n\t}\n\n\tT zero_start() {\n\t\tif(L.empty()) {\n\t\t\treturn numeric_limits<T>::min();\n\t\t} else {\n\t\t\treturn *L.rbegin() + offset_l;\n\t\t}\n\t}\n\n\tT zero_end() {\n\t\tif(R.empty()) {\n\t\t\treturn numeric_limits<T>::max();\n\t\t} else {\n\t\t\treturn *R.begin() + offset_r;\n\t\t} \n\t}\n\n\tinline size_t size() {\n\t\treturn L.size() + R.size();\n\t}\n\t\n\t/* Add the function f(x) = height + |x - center| to the current slope trick. */\n\tvoid add_simple(const T &center, const T &height = 0) {\n\t\tT s = zero_start(), e = zero_end();\n\t\tzero_height += height;\n\t\tif(s <= center && center <= e) {\n\t\t\tL.insert(center - offset_l);\n\t\t\tR.insert(center - offset_r);\n\t\t} else if(center < s) {\n\t\t\tL.insert(center - offset_l);\n\t\t\tL.insert(center - offset_l);\n\t\t\tL.erase(prev(L.end()));\n\t\t\tR.insert(s - offset_r);\t\t\t\t\t\n\t\t\tzero_height += abs(center - s);\t\n\t\t} else {\n\t\t\tR.insert(center - offset_r);\n\t\t\tR.insert(center - offset_r);\n\t\t\tR.erase(R.begin());\t\n\t\t\tL.insert(e - offset_l);\n\t\t\tzero_height += abs(center - e);\t\n\t\t}\n\t}\n\n\t/* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' <= x.  */ \n\tvoid prefix_min() {\n\t\toffset_r = 0;\n\t\tR.clear();\n\t}\n\n\t/* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' >= x.  */ \n\tvoid suffix_min() {\n\t\toffset_l = 0;\n\t\tL.clear();\n\t}\n\n\t/* 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.  */ \n\tvoid local_min(const T &strip_width) {\n\t\tif(!L.empty()) {\n\t\t\toffset_l -= strip_width;\n\t\t}\n\n\t\tif(!R.empty()) {\n\t\t\toffset_r += strip_width;\n\t\t}\n\t}\n\n\tvoid add(const slope_trick &other) {\n\t\t// TODO: Add arbitrary slope trick.\n\t}\n\n\tvoid add_with_destroy(slope_trick &other) {\n\t\t// TODO: Add using small to large.\n\t}\n};\n\nint n;\nint a[MAXN];\n\nvoid read() {\n\tcin >> n;\n\tfor(int i = 0; i < n; i++) {\n\t\tcin >> a[i];\n\t}\n}\n\nvoid solve() {\n\tslope_trick<int64_t> dp;\n\tfor(int i = 0; i < n; i++) {\n\t\ta[i] -= i;\n\t\tdp.add_simple(a[i]);\n\t\tdp.prefix_min();\n\t}\n\n\tcout << dp.zero_height << endl;\n}\n\nint main() {\n\tios_base::sync_with_stdio(false);\n\tcin.tie(nullptr);\n\n\tint T = 1;\n\t//cin >> T;\n\tfor(int test = 1; test <= T; test++) {\n\t\tread();\n\t\t//cout << \"Case #\" << test << \": \";\n\t\tsolve();\n\t}\n\n\treturn 0;\n}\n\n"
  },
  {
    "path": "other/dp_optimizations/slope_trick_priority_queue.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\n#define SZ(x) ((int)x.size())\n#define ALL(V) V.begin(), V.end()\n#define lb lower_bound\n#define ub upper_bound\n#define pb push_back\n\nusing namespace std;\ntemplate<class T, class T1> int chkmin(T &x, const T1 &y) { return x > y ? x = y, 1 : 0; }\ntemplate<class T, class T1> int chkmax(T &x, const T1 &y) { return x < y ? x = y, 1 : 0; }\nconst int MAXN = (1 << 20);\n\ntemplate<typename T>\nstruct slope_trick {\n\tT offset_l, offset_r, zero_height;\n\tpriority_queue<T> L;\n\tpriority_queue<T, vector<T>, greater<T>> R;\n\n\tslope_trick() {\n\t\toffset_l = 0;\n\t\toffset_r = 0;\n\t\tzero_height = 0;\n\t}\n\n\tT zero_start() {\n\t\tif(L.empty()) {\n\t\t\treturn numeric_limits<T>::min();\n\t\t} else {\n\t\t\treturn L.top() + offset_l;\n\t\t}\n\t}\n\n\tT zero_end() {\n\t\tif(R.empty()) {\n\t\t\treturn numeric_limits<T>::max();\n\t\t} else {\n\t\t\treturn R.top() + offset_r;\n\t\t} \n\t}\n\n\t/* Add the function f(x) = height + |x - center| to the current slope trick. */\n\tvoid add_simple(const T &center, const T &height = 0) {\n\t\tT s = zero_start(), e = zero_end();\n\t\tzero_height += height;\n\t\tif(s <= center && center <= e) {\n\t\t\tL.push(center - offset_l);\n\t\t\tR.push(center - offset_r);\n\t\t} else if(center < s) {\n\t\t\tL.push(center - offset_l);\n\t\t\tL.push(center - offset_l);\n\t\t\tL.pop();\n\t\t\tR.push(s - offset_r);\t\t\t\t\t\n\t\t\tzero_height += abs(center - s);\t\n\t\t} else {\n\t\t\tR.push(center - offset_r);\n\t\t\tR.push(center - offset_r);\n\t\t\tR.pop();\t\n\t\t\tL.push(e - offset_l);\n\t\t\tzero_height += abs(center - e);\t\n\t\t}\n\t}\n\n\t/* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' <= x.  */ \n\tvoid prefix_min() {\n\t\toffset_r = 0;\n\t\twhile(!R.empty()) {\n\t\t\tR.pop();\n\t\t}\n\t}\n\n\t/* Update the current slope trick to its prefix minimum - i.e. f'(x) = min f(x') for all x' >= x.  */ \n\tvoid suffix_min() {\n\t\toffset_l = 0;\n\t\twhile(!L.empty()) {\n\t\t\tL.pop();\n\t\t}\n\t}\n\n\t/* 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.  */ \n\tvoid local_min(const T &strip_width) {\n\t\tif(!L.empty()) {\n\t\t\toffset_l -= strip_width;\n\t\t}\n\n\t\tif(!R.empty()) {\n\t\t\toffset_r += strip_width;\n\t\t}\n\t}\n};\n\nint n;\nint a[MAXN];\n\nvoid read() {\n\tcin >> n;\n\tfor(int i = 0; i < n; i++) {\n\t\tcin >> a[i];\n\t}\n}\n\nvoid solve() {\n\tslope_trick<int64_t> dp;\n\tfor(int i = 0; i < n; i++) {\n\t\ta[i] -= i;\n\t\tdp.add_simple(a[i]);\n\t\tdp.prefix_min();\n\t}\n\n\tcout << dp.zero_height << endl;\n}\n\nint main() {\n\tios_base::sync_with_stdio(false);\n\tcin.tie(nullptr);\n\n\tint T = 1;\n\t//cin >> T;\n\tfor(int test = 1; test <= T; test++) {\n\t\tread();\n\t\t//cout << \"Case #\" << test << \": \";\n\t\tsolve();\n\t}\n\n\treturn 0;\n}\n\n"
  },
  {
    "path": "other/queries/mo.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n\nusing namespace std;\nconst int MAXN = (1 << 20);\n\nstruct query\n{\n\tint l, r, block;\n\tint idx;\n\n\tquery() {l = -1; r = -1; block = -1; idx = -1;}\n\tquery(int _l, int _r, int i)\n\t{\n\t\tl = _l;\n\t\tr = _r;\n\t\tidx = i;\n\t}\n};\n\nbool cmp(query a, query b)\n{\n\tif(a.block != b.block) return a.block < b.block;\n\treturn a.r < b.r;\n}\n\nint n, m, len, sq, item;\n\nvoid read()\n{\n\tcin >> n >> m;\n\n}\n\nint ans, answer[MAXN];\n\nvoid add(int idx)\n{\n\n}\n\nvoid del(int idx)\n{\t\n\n}\t\t\n\nquery q[MAXN];\n\nvoid solve()\n{\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\tint l, r;\n\t\tcin >> l >> r;\n\t\tq[i] = query(l - 1, r - 1, i);\n\t}\n\n\tsq = sqrt(n);\n\tfor(int i = 0; i < m; i++) q[i].block = q[i].l / sq;\n\tsort(q, q + m, cmp);\n\n\tint l = q[0].l, r = q[0].r;\n\tfor(int i = l; i <= r; i++)\n\t\tadd(i);\n\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\twhile(l < q[i].l) del(l++);\n\t\twhile(l > q[i].l) add(--l);\n\t\twhile(r < q[i].r) add(++r);\n\t\twhile(r > q[i].r) del(r--);\n\t\t\n\t\tanswer[q[i].idx] = ans;\n\t}\n\n\tfor(int i = 0; i < m; i++)\n\t\tcout << answer[i] << endl;\n}\n\nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n\n\tread();\n\tsolve();\n\treturn 0;\n}\n\n"
  },
  {
    "path": "other/queries/mo_dsu.cpp",
    "content": "#include <bits/stdc++.h>\n#define endl '\\n'\n \nusing namespace std;\nconst int MAXN = (1 << 20);\n \nstruct query\n{\n\tint l, r, idx;\n\tquery() {l = 0; r = 0; idx = 0;}\n\tquery(int _l, int _r, int _idx)\n\t{\n\t\tl = _l;\n\t\tr = _r;\n\t\tidx = _idx;\n\t}\n};\n \nstruct persistent_dsu\n{\n\tstruct state\n\t{\t\n\t\tint u, ru, v, rv;\n\t\tstate() {u = 0; ru = 0; v = 0; rv = 0;}\n\t\tstate(int _u, int _ru, int _v, int _rv)\n\t\t{\n\t\t\tu = _u;\n\t\t\tru = _ru;\n\t\t\tv = _v;\n\t\t\trv = _rv;\n\t\t}\n\t};\n \n\tint cnt;\n\tint depth[MAXN], par[MAXN];\n\tstack<state> st;\t\n \n\tpersistent_dsu() \n\t{\n\t\tcnt = 0; \n\t\tmemset(depth, 0, sizeof(depth)); \n\t\tmemset(par, 0, sizeof(par));\n\t\twhile(!st.empty()) st.pop();\n\t}\n \n\tvoid init(int _sz)\n\t{\n\t\tcnt = _sz;\n\t\tfor(int i = 0; i <= _sz; i++)\n\t\t\tpar[i] = i, depth[i] = 1;\n\t}\n \n\tint root(int x)\n\t{\n\t\tif(x == par[x]) return x;\n\t\treturn root(par[x]);\n\t}\n \n\tbool connected(int x, int y)\n\t{\n\t\treturn root(x) == root(y);\n\t}\n \n\tvoid unite(int x, int y)\n\t{\n\t\tint rx = root(x), ry = root(y);\n\t\tif(rx == ry) return;\n \n\t\tif(depth[rx] < depth[ry])\n\t\t\tpar[rx] = ry;\n\t\telse if(depth[ry] < depth[rx])\n\t\t\tpar[ry] = rx;\n\t\telse par[rx] = ry, depth[ry]++;\n\t\n\t\tcnt--;\n\t\tst.push(state(rx, depth[rx], ry, depth[ry]));\n\t\t\n\t}\n\n\tvoid snapshot() { st.push(state(-1, -1, -1, -1)); }\n \n\tvoid rollback()\n\t{\n\t\twhile(!st.empty())\n\t\t{\n\t\t\tif(st.top().u == -1)\n\t\t\t\treturn;\n \n\t\t\t++cnt;\n\t\t\tpar[st.top().u] = st.top().u;\n\t\t\tpar[st.top().v] = st.top().v;\n\t\t\tdepth[st.top().u] = st.top().ru;\n\t\t\tdepth[st.top().v] = st.top().rv;\n\t\t\tst.pop();\n\t\t}\n\t}\n};\n \nstruct edge\n{\n\tint u, v;\n\tedge() {u = 0; v = 0;}\n\tedge(int _u, int _v)\n\t{\n\t\tu = _u;\n\t\tv = _v;\n\t}\n};\n \nint n, ed, m;\nedge a[MAXN];\nquery q[MAXN];\n \nvoid read()\n{\n\tcin >> n >> ed >> m;\t\n \n\tfor(int i = 1; i <= ed; i++)\n\t{\n\t\tint u, v;\n\t\tcin >> u >> v;\n\t\ta[i] = edge(u, v);\n\t}\n}\n \nint rt, cnt_q;\npersistent_dsu d;\n \nbool cmp(query fir, query sec)\n{\n\tif(fir.l / rt != sec.l / rt) return fir.l / rt < sec.l / rt;\n\treturn fir.r < sec.r;\n}\n \nint answer[MAXN];\nvoid add(int idx) { d.unite(a[idx].u, a[idx].v); }\n \nvoid solve()\n{\n\td.init(n);\n\td.snapshot();\n\trt = sqrt(ed);\n\tcnt_q = 0;\n \n\tint fm = m;\n\tfor(int i = 0; i < m; i++)\n\t{\n\t\tint l, r;\n\t\tcin >> l >> r;\n\t\t\n\t\tif(r - l + 1 <= rt)\n\t\t{\n\t\t\tfor(int k = l; k <= r; k++) add(k);\n\t\t\tanswer[i] = d.cnt;\n\t\t\td.rollback();\n\t\t\tcontinue;\t\n\t\t}\n \n\t\tq[cnt_q++] = query(l, r, i);\n\t}\n \n\tm = cnt_q;\n\tsort(q, q + m, cmp);\n\tint last, border, last_block = -1, block;\n \n\tfor(int i = 0; i < m; i++)\n\t{\n\t\tblock = q[i].l / rt;\n\t\tif(last_block != block)\n\t\t{\n\t\t\td.init(n);\n\t\t\tborder = rt * (block + 1);\n\t\t\tlast = border;\n\t\t}\n \n\t\tlast_block = block;\n\t\tfor(int k = last + 1; k <= q[i].r; k++) add(k);\n\t\td.snapshot();\n \n\t\tfor(int k = q[i].l; k <= border; k++) add(k);\n\t\tanswer[q[i].idx] = d.cnt;\n\t\td.rollback();\n\n\t\tlast = q[i].r;\n\n\t}\n \n\tfor(int i = 0; i < fm; i++)\n\t\tcout << answer[i] << endl;\n}\n \nint main()\n{\n\tios_base::sync_with_stdio(false);\n\tcin.tie(NULL);\n \n\tread();\n\tsolve();\n\treturn 0;\n}\n"
  },
  {
    "path": "other/queries/mo_online.cpp",
    "content": "#include <bits/stdc++.h>\r\n#define endl '\\n'\r\n\r\nusing namespace std;\r\nconst int MAXN = (int)1e5 + 42;\r\nconst int B = 2172;\r\n\r\nint n, q;\r\nint a[MAXN];\r\n\r\nvoid read()\r\n{\r\n\tcin >> n >> q;\r\n\tfor(int i = 0; i < n; i++)\r\n\t\tcin >> a[i];\r\n}\r\n\r\nstruct my_set\r\n{\r\n\tint answer;\r\n    unordered_map<int, int> cnt;\r\n    my_set() { answer = 0; cnt.clear(); }\r\n\r\n    void insert(int val)\r\n    {\r\n\t\tint memo = ++cnt[val];\r\n\t\tif(memo == 1) answer++;\r\n    }\r\n\r\n    void erase(int val)\r\n    {\r\n\t\tint memo = --cnt[val];\r\n\t\tif(memo == 0) answer--;\r\n    }\r\n\r\n    void clear()\r\n    {\r\n    \tanswer = 0;\r\n    \tcnt.clear();\r\n    }\r\n\r\n\tint query() { return answer; }\r\n};\r\n\r\n\r\nint st_block[MAXN / B + 42], en_block[MAXN / B + 42], cnt_blocks = 0;\r\nmy_set st[(MAXN / B + 1) * (MAXN / B + 1) + 42], nw_st;\r\n\r\nint query(int l, int r)\r\n{\r\n\tint Lblock = l / B, Rblock = r / B;\r\n\tif(r != en_block[Rblock]) Rblock--;\r\n\tif(l != st_block[Lblock]) Lblock++;\r\n\r\n\tif(Rblock < Lblock)\r\n\t{\r\n\t\tnw_st.clear();\r\n\t\tfor(int i = l; i <= r; i++)\r\n\t\t\tnw_st.insert(a[i]);\r\n        return nw_st.query();\r\n\t}\r\n\r\n\tint mid = Lblock * cnt_blocks + Rblock;\r\n    for(int i = l; i < st_block[Lblock]; i++) st[mid].insert(a[i]);\r\n\tfor(int i = en_block[Rblock] + 1; i <= r; i++) st[mid].insert(a[i]);\r\n\r\n\tint answer = st[mid].query();\r\n\r\n\tfor(int i = l; i < st_block[Lblock]; i++) st[mid].erase(a[i]);\r\n\tfor(int i = en_block[Rblock] + 1; i <= r; i++) st[mid].erase(a[i]);\r\n\r\n\treturn answer;\r\n}\r\n\r\nvoid update(int mid, int pos, int val)\r\n{\r\n\tst[mid].erase(a[pos]);\r\n\tst[mid].insert(val);\r\n}\r\n\r\nvoid solve()\r\n{\r\n\tfor(int i = 0; i < n; i++)\r\n\t{\r\n\t\tif(i % B == 0) st_block[i / B] = i, cnt_blocks++;\r\n\t\tif(i % B == B - 1 || i == n - 1)\r\n\t\t\ten_block[i / B] = i;\r\n\t}\r\n\r\n\tfor(int i = 0; i < cnt_blocks; i++)\r\n\t\tfor(int j = i; j < cnt_blocks; j++)\r\n\t\t{\r\n\t\t\tint mid = i * cnt_blocks + j;\r\n\t\t\tst[mid] = my_set();\r\n\t\t\tfor(int p = st_block[i]; p <= en_block[j]; p++)\r\n\t\t\t\tst[mid].insert(a[p]);\r\n\t\t}\r\n\r\n    for(int p = 0; p < q; p++)\r\n\t{\r\n        int type;\r\n        cin >> type;\r\n\r\n        if(type == 1)\r\n\t\t{\r\n\t\t\tint l, r;\r\n\t\t\tcin >> l >> r;\r\n\t\t\tcout << query(l, r) << endl;\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\tint pos, val;\r\n\t\t\tcin >> pos >> val;\r\n\r\n            for(int i = 0; i < cnt_blocks; i++)\r\n\t\t\t\tfor(int j = i; j < cnt_blocks; j++)\r\n\t\t\t\t\tif(st_block[i] <= pos && pos <= en_block[j])\r\n\t\t\t\t\t\tupdate(i * cnt_blocks + j, pos, val);\r\n\r\n\t\t\ta[pos] = val;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nint main()\r\n{\r\n\tios_base::sync_with_stdio(false);\r\n\tcin.tie(NULL);\r\n\r\n\tread();\r\n\tsolve();\r\n\treturn 0;\r\n}\r\n"
  },
  {
    "path": "other/queries/offline_centroid_queries.cpp",
    "content": "// This is from https://codeforces.com/contest/1902/problem/F\n\n#include <bits/stdc++.h>\n\nusing namespace std;\n\ntemplate<class T, class T1>\nint chkmin(T &x, const T1 &y) {\n    return x > y ? x = y, 1 : 0;\n}\n\ntemplate<class T, class T1>\nint chkmax(T &x, const T1 &y) {\n    return x < y ? x = y, 1 : 0;\n}\n\ntemplate<typename T1, typename T2>\nostream &operator<<(ostream &out, const pair<T1, T2> &x) {\n    return out << x.first << ' ' << x.second;\n}\n\ntemplate<typename T1, typename T2>\nistream &operator>>(istream &in, pair<T1, T2> &x) {\n    return in >> x.first >> x.second;\n}\n\ntemplate<typename T>\nistream &operator>>(istream &in, vector<T> &a) {\n    for(auto &x: a) {\n        in >> x;\n    }\n    return in;\n};\n\ntemplate<typename T>\nostream &operator<<(ostream &out, vector<T> &a) {\n    for(auto &x: a) {\n        out << x << ' ';\n    }\n    return out;\n};\n\ntemplate<class T>\nstruct basis {\n    int max_log;\n    vector<T> base;\n\n    void init(int _max_log) {\n        max_log = _max_log;\n        base.assign(max_log, 0);\n    }\n\n    void add(T val) {\n        for(int i = max_log - 1; i >= 0; i--) {\n            if((val >> i) & 1) {\n                if(!base[i]) {\n                    base[i] = val;\n                    return;\n                } else {\n                    val ^= base[i];\n                }\n            }\n        }\n    }\n\n    inline int size() {\n        int sz = 0;\n        for(int i = 0; i < max_log; i++) {\n            sz += (bool)(base[i]);\n        }\n        return sz;\n    }\n\n    T max_xor() {\n        T res = 0;\n        for(int i = max_log - 1; i >= 0; i--) {\n            if(!((res >> i) & 1) && base[i]) {\n                res ^= base[i];\n            }\n        }\n\n        return res;\n    }\n\n    bool can_create(T val) {\n        for(int i = max_log - 1; i >= 0; i--) {\n            if(((val >> i) & 1) && base[i]) {\n                val ^= base[i];\n            }\n        }\n\n        return (val == 0);\n    }\n\n    vector<T> get_basis() {\n        vector<T> res;\n        for(int i = 0; i < max_log; i++) {\n            if(base[i]) {\n                res.push_back(base[i]);\n            }\n        }\n        return res;\n    }\n\n    basis<T> merge(basis<T> other) {\n        if(max_log < other.max_log) {\n            return other.merge(*this);\n        }\n\n        basis<T> res = *this;\n        for(auto x: other.base) {\n            if(x) {\n                res.add(x);\n            }\n        }\n        return res;\n    }\n};\n\nconst int MAXLOG = 20;\n\nint n;\nvector<vector<int>> adj;\nvector<int> a;\n\nvoid read() {\n    cin >> n;\n    adj.assign(n, {});\n    a.resize(n);\n    cin >> a;\n    for(int i = 0; i < n - 1; i++) {\n        int u, v;\n        cin >> u >> v;\n        u--, v--;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n}\n\nvector<basis<int>> bs;\nvector<pair<pair<int, int>, int>> queries;\nvector<int> ans, sz, marker;\nvector<bool> used;\n\nint get_size(int v, int p) {\n    sz[v] = 1;\n    for(int u: adj[v]) {\n        if(u != p && !used[u]) {\n            sz[v] += get_size(u, v);\n        }\n    }\n    return sz[v];\n}\n\nvoid dfs_basis(int v, int p, basis<int> pref_bs) {\n    basis<int> nw_bs = pref_bs;\n    nw_bs.add(a[v]);\n    bs[v] = nw_bs;\n    for(auto u: adj[v]) {\n        if(u != p && !used[u]) {\n            dfs_basis(u, v, nw_bs);\n        }\n    }\n}\n\nvoid dfs_marker(int v, int p, int mark) {\n    marker[v] = mark;\n    for(int u: adj[v]) {\n        if(u != p && !used[u]) {\n            dfs_marker(u, v, mark);\n        }\n    }\n}\n\nvoid decompose(int u, vector<int> qidx) {\n    get_size(u, -1);\n    int n = sz[u], centroid = u, p = -1;\n    while(true) {\n        int nxt = -1;\n        for(int v: adj[centroid]) {\n            if(v != p && !used[v] && sz[v] > n / 2) {\n                nxt = v;\n                break;\n            }\n        }\n\n        if(nxt != -1) {\n            p = centroid;\n            centroid = nxt;\n        } else {\n            break;\n        }\n    }\n\n    used[centroid] = true;\n    basis<int> pref_bs;\n    pref_bs.init(MAXLOG);\n    pref_bs.add(a[centroid]);\n    bs[centroid] = pref_bs;\n\n    int mark = 0;\n    vector<vector<int>> children_queries(adj[centroid].size());\n    for(int v: adj[centroid]) {\n        if(!used[v]) {\n            dfs_marker(v, centroid, mark);\n            dfs_basis(v, centroid, pref_bs);\n        }\n        mark++;\n    }\n\n    marker[centroid] = mark;\n    for(int idx: qidx) {\n        auto [xy, k] = queries[idx];\n        auto [x, y] = xy;\n        if(marker[x] == marker[y] && x != centroid) {\n            children_queries[marker[x]].push_back(idx);\n        } else {\n            basis<int> q_basis = bs[x].merge(bs[y]);\n            if(q_basis.can_create(k)) {\n                ans[idx] = 1;\n            } else {\n                ans[idx] = 0;\n            }\n        }\n    }\n\n    int i = 0;\n    for(int v: adj[centroid]) {\n        if(!used[v] && children_queries[i].size() > 0) {\n            decompose(v, children_queries[i]);\n        }\n        i++;\n    }\n}\n\nvoid solve() {\n    bs.resize(n);\n    sz.resize(n);\n    used.assign(n, false);\n    marker.assign(n, 0);\n\n    int q;\n    cin >> q;\n    queries.resize(q);\n    for(int i = 0; i < q; i++) {\n        int x, y, k;\n        cin >> x >> y >> k;\n        x--, y--;\n        queries[i] = {{x, y}, k};\n    }\n\n    vector<int> qidx(q);\n    ans.resize(q);\n    iota(qidx.begin(), qidx.end(), 0);\n    decompose(0, qidx);\n\n    for(int i = 0; i < q; i++) {\n        if(ans[i] == 1) {\n            cout << \"YES\\n\";\n        } else {\n            cout << \"NO\\n\";\n        }\n    }\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int T = 1;\n    // cin >> T;\n    for(int test = 1; test <= T; test++) {\n        read();\n        // cout << \"Case #\" << test << \": \";\n        solve();\n    }\n\n    return 0;\n}\n"
  },
  {
    "path": "other/utils/count_inversions.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nint64_t count_inversions(int *start, int *end) {\n    if(end - start <= 1) {\n        return 0;\n    }\n \n    int *mid = start + (end - start) / 2;\n    int64_t ans = count_inversions(start, mid) + count_inversions(mid, end);\n \n    vector<int> temp;\n    for(int *i = start, *j = mid; i != mid || j != end; ) {\n        if(i == mid) {\n            temp.push_back(*j++);\n        } else if(j == end) {\n            temp.push_back(*i++);\n        } else if(*i <= *j) {\n            temp.push_back(*i++);\n        } else {\n            ans += mid - i;\n            temp.push_back(*j++);\n        }\n    }\n \n    copy(temp.begin(), temp.end(), start);\n    return ans;\n}\n"
  },
  {
    "path": "strings/aho_corasick.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T = string>\nclass AhoCorasick {\n  private:\n    using G = conditional_t<\n        is_same_v<T, const char*> || is_same_v<T, char*> || is_array_v<T>, char,\n        typename T::value_type>;\n\n    struct State {\n        map<G, int> to;\n        int link;\n        int word_id;\n        State() : link(0), word_id(-1) {}\n    };\n\n  public:\n    vector<State> states;\n\n    AhoCorasick() { clear(); }\n\n    void clear() {\n        states.clear();\n        states.emplace_back();\n    }\n\n    void add_word(const T& word, int id = -1) {\n        int u = 0;\n        for(const G& c: word) {\n            if(!states[u].to.count(c)) {\n                states[u].to[c] = states.size();\n                states.emplace_back();\n            }\n            u = states[u].to[c];\n        }\n        states[u].word_id = id;\n    }\n\n    void build() {\n        queue<int> Q;\n        states[0].link = -1;\n\n        for(auto& [c, v]: states[0].to) {\n            states[v].link = 0;\n            Q.push(v);\n        }\n\n        while(!Q.empty()) {\n            int u = Q.front();\n            Q.pop();\n\n            for(auto& [c, v]: states[u].to) {\n                int j = states[u].link;\n                while(j != -1 && !states[j].to.count(c)) {\n                    j = states[j].link;\n                }\n                states[v].link = (j == -1) ? 0 : states[j].to[c];\n                Q.push(v);\n            }\n        }\n    }\n\n    int go(int u, const G& c) const {\n        while(u != -1 && !states[u].to.count(c)) {\n            u = states[u].link;\n        }\n        return (u == -1) ? 0 : states[u].to.at(c);\n    }\n\n    int link(int u) const { return states[u].link; }\n    int word_id(int u) const { return states[u].word_id; }\n    int size() const { return states.size(); }\n\n    vector<int> traverse(const T& text) const {\n        vector<int> result;\n        result.reserve(text.size());\n        int u = 0;\n        for(const G& c: text) {\n            u = go(u, c);\n            result.push_back(u);\n        }\n        return result;\n    }\n\n    vector<vector<int>> build_link_tree() const {\n        vector<vector<int>> adj(states.size());\n        for(int i = 1; i < (int)states.size(); i++) {\n            adj[states[i].link].push_back(i);\n        }\n        return adj;\n    }\n};\n"
  },
  {
    "path": "strings/hashing.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass HashMeta {\n  private:\n    void set_random_base() {\n        seed_seq seed{\n            (uint32_t)chrono::duration_cast<chrono::nanoseconds>(\n                chrono::high_resolution_clock::now().time_since_epoch()\n            )\n                .count(),\n            (uint32_t)random_device()(), (uint32_t)42\n        };\n        mt19937 rng(seed);\n        base = uniform_int_distribution<uint64_t>(0, mod - 1)(rng);\n    }\n\n    void precompute_base_pow(size_t n) {\n        base_pow.resize(n);\n        base_pow[0] = 1;\n        for(size_t i = 1; i < n; i++) {\n            base_pow[i] = mul(base_pow[i - 1], base);\n        }\n    }\n\n    static constexpr uint64_t add(uint64_t a, uint64_t b) {\n        a += b + 1;\n        a = (a & mod) + (a >> 61);\n        return a - 1;\n    }\n\n    static constexpr uint64_t sub(uint64_t a, uint64_t b) {\n        return add(a, mod - b);\n    }\n\n    static constexpr uint64_t mul(uint64_t a, uint64_t b) {\n        uint64_t l1 = (uint32_t)a, h1 = a >> 32, l2 = (uint32_t)b, h2 = b >> 32;\n        uint64_t l = l1 * l2, m = l1 * h2 + l2 * h1, h = h1 * h2;\n        uint64_t ret =\n            (l & mod) + (l >> 61) + (h << 3) + (m >> 29) + (m << 35 >> 3) + 1;\n        ret = (ret & mod) + (ret >> 61);\n        ret = (ret & mod) + (ret >> 61);\n        return ret - 1;\n    }\n\n  public:\n    class hash_t {\n        uint64_t h;\n\n      public:\n        hash_t() : h(0) {}\n        hash_t(uint64_t h) : h(h) {}\n        operator uint64_t() const { return h; }\n\n        hash_t& operator+=(const hash_t& other) {\n            h = add(h, other.h);\n            return *this;\n        }\n\n        hash_t& operator-=(const hash_t& other) {\n            h = sub(h, other.h);\n            return *this;\n        }\n\n        hash_t& operator*=(const hash_t& other) {\n            h = mul(h, other.h);\n            return *this;\n        }\n\n        hash_t operator+(const hash_t& other) const {\n            return hash_t(*this) += other;\n        }\n        hash_t operator-(const hash_t& other) const {\n            return hash_t(*this) -= other;\n        }\n        hash_t operator*(const hash_t& other) const {\n            return hash_t(*this) *= other;\n        }\n\n        bool operator==(const hash_t& other) const { return h == other.h; }\n        bool operator!=(const hash_t& other) const { return h != other.h; }\n\n        // For use in std::map and std::set\n        bool operator<(const hash_t& other) const { return h < other.h; }\n    };\n\n    uint64_t base;\n    vector<hash_t> base_pow;\n    static constexpr uint64_t mod = (1ull << 61) - 1;\n\n    void init(size_t n) {\n        set_random_base();\n        precompute_base_pow(n);\n    }\n\n    template<typename T>\n    vector<hash_t> rabin_karp(const T& container) {\n        vector<hash_t> h(container.size());\n        for(size_t i = 0; i < container.size(); i++) {\n            h[i] = (i ? h[i - 1] : hash_t(0)) * hash_t(base) +\n                   hash_t(container[i]);\n        }\n        return h;\n    }\n\n    hash_t hash_range(int l, int r, const vector<hash_t>& h) {\n        if(l == 0) {\n            return h[r];\n        }\n        return h[r] - h[l - 1] * base_pow[r - l + 1];\n    }\n};\n\n// HashMeta hash_meta;\n// using hash_t = HashMeta::hash_t;\n"
  },
  {
    "path": "strings/suffix_array.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T = string>\nclass SuffixArray {\n  private:\n    using G = conditional_t<\n        is_same_v<T, const char*> || is_same_v<T, char*> || is_array_v<T>, char,\n        typename T::value_type>;\n\n    void build_sa(const T& s) {\n        sa.resize(n);\n        rnk.resize(n);\n        vector<int> tmp(n);\n\n        for(int i = 0; i < n; i++) {\n            sa[i] = i;\n            rnk[i] = (int)s[i];\n        }\n\n        for(int k = 1; k < n; k <<= 1) {\n            auto cmp = [&](int x, int y) {\n                if(rnk[x] != rnk[y]) {\n                    return rnk[x] < rnk[y];\n                }\n\n                int rx = x + k < n ? rnk[x + k] : -1;\n                int ry = y + k < n ? rnk[y + k] : -1;\n                return rx < ry;\n            };\n\n            sort(sa.begin(), sa.end(), cmp);\n            tmp[sa[0]] = 0;\n            for(int i = 1; i < n; i++) {\n                tmp[sa[i]] = tmp[sa[i - 1]] + (cmp(sa[i - 1], sa[i]) ? 1 : 0);\n            }\n\n            rnk = tmp;\n            if(rnk[sa[n - 1]] == n - 1) {\n                break;\n            }\n        }\n    }\n\n    void build_lcp(const T& s) {\n        lcp.assign(n, 0);\n        int h = 0;\n        for(int i = 0; i < n; i++) {\n            if(rnk[i] > 0) {\n                int j = sa[rnk[i] - 1];\n                while(i + h < n && j + h < n && s[i + h] == s[j + h]) {\n                    h++;\n                }\n\n                lcp[rnk[i]] = h;\n                if(h > 0) {\n                    h--;\n                }\n            } else {\n                h = 0;\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<int> sa, rnk, lcp;\n\n    SuffixArray() : n(0) {}\n    SuffixArray(const T& s) { init(s); }\n\n    void clear() {\n        n = 0;\n        sa.clear();\n        rnk.clear();\n        lcp.clear();\n    }\n\n    void init(const T& s) {\n        clear();\n        n = (int)size(s);\n        if(n == 0) {\n            return;\n        }\n\n        build_sa(s);\n        build_lcp(s);\n    }\n};\n"
  },
  {
    "path": "strings/suffix_automaton.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<class T = string>\nclass SuffixAutomaton {\n  private:\n    using G = conditional_t<\n        is_same_v<T, const char*> || is_same_v<T, char*> || is_array_v<T>, char,\n        typename T::value_type>;\n\n    struct State {\n        map<G, int> to;\n        int len;\n        int link;\n        State(int l = 0, int lnk = -1) : len(l), link(lnk) {}\n    };\n\n    int check_replace_with_clone(int p, G c) {\n        int q = states[p].to[c];\n        if(states[p].len + 1 == states[q].len) {\n            return q;\n        }\n\n        int clone = states.size();\n        states.emplace_back(states[p].len + 1, states[q].link);\n        states[clone].to = states[q].to;\n        while(p >= 0 && states[p].to[c] == q) {\n            states[p].to[c] = clone;\n            p = states[p].link;\n        }\n        states[q].link = clone;\n        return clone;\n    }\n\n  public:\n    int last;\n    vector<State> states;\n\n    SuffixAutomaton() : last(0) { clear(); }\n    SuffixAutomaton(const T& s) { init(s); }\n\n    void add_letter(G c) {\n        if(states[last].to.count(c)) {\n            int clone = check_replace_with_clone(last, c);\n            last = clone;\n            return;\n        }\n\n        int p = last;\n        last = states.size();\n        states.emplace_back(states[p].len + 1);\n\n        while(p >= 0 && !states[p].to.count(c)) {\n            states[p].to[c] = last;\n            p = states[p].link;\n        }\n\n        if(p == -1) {\n            states[last].link = 0;\n            return;\n        }\n\n        int q_or_clone = check_replace_with_clone(p, c);\n        states[last].link = q_or_clone;\n    }\n\n    void add_string(const T& s) {\n        last = 0;\n        for(char c: s) {\n            add_letter(c);\n        }\n    }\n\n    void clear() {\n        states.clear();\n        states.emplace_back();\n        last = 0;\n    }\n\n    void init(const T& s) {\n        clear();\n        add_string(s);\n    }\n\n    vector<vector<int>> build_suffix_link_tree() {\n        vector<vector<int>> adj(states.size());\n        for(int i = 1; i < (int)states.size(); i++) {\n            adj[states[i].link].push_back(i);\n        }\n        return adj;\n    }\n\n    vector<vector<int>> states_by_length() {\n        vector<vector<int>> ret(states.size()); \n        for(int i = 0; i < (int)states.size(); i++) {\n            ret[states[i].len].push_back(i);\n        }\n        return ret;\n    }\n};\n"
  },
  {
    "path": "tree/centroid_decomposition.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\ntemplate<\n    void (*process)(int, const vector<vector<int>> &, const vector<bool> &)>\nclass CentroidDecomposition {\n  private:\n    int n;\n    vector<vector<int>> adj;\n    vector<bool> blocked;\n    vector<int> subtree_size;\n\n    int dfs(int u, int pr) {\n        subtree_size[u] = 1;\n        for(int v: adj[u]) {\n            if(v != pr && !blocked[v]) {\n                subtree_size[u] += dfs(v, u);\n            }\n        }\n        return subtree_size[u];\n    }\n\n    int find_centroid(int u, int pr, int n) {\n        for(int v: adj[u]) {\n            if(v != pr && !blocked[v] && subtree_size[v] > n / 2) {\n                return find_centroid(v, u, n);\n            }\n        }\n        return u;\n    }\n\n  public:\n    vector<int> link, centroid_depth;\n\n    CentroidDecomposition(vector<vector<int>> adj = {}, int root = 0)\n        : adj(adj) {\n        n = adj.size();\n        if(n > 0) {\n            blocked.assign(n, false);\n            link.assign(n, -1);\n            centroid_depth.assign(n, -1);\n            subtree_size.assign(n, 0);\n            decompose(root);\n        }\n    }\n\n    void decompose(int u, int prev_cen = -1, int depth = 0) {\n        int n_here = dfs(u, -1);\n        int cen = find_centroid(u, -1, n_here);\n\n        link[cen] = prev_cen;\n        centroid_depth[cen] = depth;\n        process(cen, adj, blocked);\n\n        blocked[cen] = true;\n        for(int v: adj[cen]) {\n            if(!blocked[v]) {\n                decompose(v, cen, depth + 1);\n            }\n        }\n        blocked[cen] = false;\n    }\n};\n \n// void blank_process(int, const vector<vector<int>> &, const vector<bool> &) {}\n// #include <coding_library/tree/lca_sparse_table.hpp>\n\n// LCAUtilsRMQ tr;\n// tr.init(n);\n// for(int i = 1; i < n; i++) {\n//     tr.add_edge(i, p[i]);\n// }\n// tr.prepare(0);\n\n// Maintain closest active node query.\n\n// CentroidDecomposition<blank_process> cd(tr.adj);\n// vector<priority_queue<pair<int, int>>> best(n), to_remove(n);\n\n// function<int(int)> closest_active = [&](int u) {\n//     int cen_root = u, ans_dist = -1, ans_node = -1;\n//     while(cen_root != -1) {\n//         while(!best[cen_root].empty() && !to_remove[cen_root].empty() &&\n//               to_remove[cen_root].top() == best[cen_root].top()) {\n//             to_remove[cen_root].pop();\n//             best[cen_root].pop();\n//         }\n//         if(!best[cen_root].empty()) {\n//             int cand = best[cen_root].top().second;\n//             int d = tr.dist(u, cand);\n//             if(ans_dist == -1 || d < ans_dist) {\n//                 ans_dist = d;\n//                 ans_node = cand;\n//             }\n//         }\n//         cen_root = cd.link[cen_root];\n//     }\n//     assert(ans_node != -1);\n//     return ans_node;\n// };\n\n// function<void(int)> activate = [&](int u) {\n//     int cen_root = u;\n//     while(cen_root != -1) {\n//         int d = tr.dist(u, cen_root);\n//         best[cen_root].push({-d, u});\n//         cen_root = cd.link[cen_root];\n//     }\n// };\n\n// function<void(int)> deactivate = [&](int u) {\n//     int cen_root = u;\n//     while(cen_root != -1) {\n//         int d = tr.dist(u, cen_root);\n//         to_remove[cen_root].push({-d, u});\n//         cen_root = cd.link[cen_root];\n//     }\n// };\n"
  },
  {
    "path": "tree/euler_order_segment_tree.cpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\ntemplate<class T, class T1>\nint chkmin(T &x, const T1 &y) {\n    return x > y ? x = y, 1 : 0;\n}\ntemplate<class T, class T1>\nint chkmax(T &x, const T1 &y) {\n    return x < y ? x = y, 1 : 0;\n}\nconst int MAXN = (1 << 20);\nconst int inf = (int)1e9 + 42;\n\nint n;\nvector<int> adj[MAXN];\n\nvoid read() {\n    cin >> n;\n    for(int i = 0; i < n - 1; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n}\n\nint st[MAXN], en[MAXN], ver[MAXN], dep[MAXN], dfs_time = 0;\nvector<array<int, 1>> dat;\nvoid pre_dfs(int u, int pr, int d = 0) {\n    en[u] = st[u] = dfs_time++;\n    ver[st[u]] = u;\n    dep[u] = d;\n\n    dat.push_back({dep[u]});\n\n    for(int v: adj[u]) {\n        if(v != pr) {\n            pre_dfs(v, u, d + 1);\n            dat.push_back({dep[u]});\n            en[u] = dfs_time++;\n            ver[en[u]] = u;\n        }\n    }\n}\n\nstruct segment_tree {\n    struct node {\n        int l, m, r, lm, mr, lmr;\n        node() { l = m = r = lm = mr = lmr = -inf; }\n\n        node(int d) {\n            l = d;\n            m = -2 * d;\n            r = d;\n            lm = -d;\n            mr = -d;\n            lmr = 0;\n        }\n    };\n\n    node merge(node a, node b) {\n        node ret;\n        ret.l = max(a.l, b.l);\n        ret.m = max(a.m, b.m);\n        ret.r = max(a.r, b.r);\n        ret.lm = max(a.lm, b.lm);\n        ret.mr = max(a.mr, b.mr);\n        ret.lmr = max(a.lmr, b.lmr);\n\n        chkmax(ret.lm, a.l + b.m);\n        chkmax(ret.mr, a.m + b.r);\n\n        chkmax(ret.lmr, a.lm + b.r);\n        chkmax(ret.lmr, a.l + b.mr);\n        return ret;\n    }\n\n    int lazy[4 * MAXN];\n    node tr[4 * MAXN];\n\n    void push(int l, int r, int idx) {\n        if(lazy[idx]) {\n            if(l != r) {\n                lazy[2 * idx + 1] ^= lazy[idx];\n                lazy[2 * idx + 2] ^= lazy[idx];\n            }\n            lazy[idx] = 0;\n        }\n    }\n\n    void init(int l, int r, int idx, const vector<array<int, 1>> &dat) {\n        if(l == r) {\n            tr[idx] = node(dat[l][0]);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        init(l, mid, 2 * idx + 1, dat);\n        init(mid + 1, r, 2 * idx + 2, dat);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    void update(int pos, int l, int r, int idx) {\n        if(l == r) {\n            // DO SOMETHING\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        if(pos <= mid) {\n            update(pos, l, mid, 2 * idx + 1);\n        } else {\n            update(pos, mid + 1, r, 2 * idx + 2);\n        }\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n\n    void update(int ql, int qr, int l, int r, int idx) {\n        push(l, r, idx);\n\n        if(ql > r || l > qr) {\n            return;\n        }\n\n        if(ql <= l && r <= qr) {\n            // DO SOMETHING\n            push(l, r, idx);\n            return;\n        }\n\n        int mid = (l + r) >> 1;\n        update(ql, qr, l, mid, 2 * idx + 1);\n        update(ql, qr, mid + 1, r, 2 * idx + 2);\n\n        tr[idx] = merge(tr[2 * idx + 1], tr[2 * idx + 2]);\n    }\n} T;\n\nvoid solve() {\n    pre_dfs(1, 1, 0);\n    T.init(0, (int)dat.size() - 1, 0, dat);\n}\n\nint main() {\n    ios_base::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    read();\n    solve();\n    return 0;\n}\n"
  },
  {
    "path": "tree/lca.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\nclass LCAUtils {\n  protected:\n    int max_log, dfs_time;\n    vector<vector<int>> par_up;\n\n    void dfs_lca(int u, int pr, int& dfs_time) {\n        in_time[u] = ++dfs_time;\n        par_up[u][0] = pr;\n        for(int i = 1; i < max_log; i++) {\n            par_up[u][i] = par_up[par_up[u][i - 1]][i - 1];\n        }\n\n        for(int v: adj[u]) {\n            if(v != pr) {\n                dfs_lca(v, u, dfs_time);\n            }\n        }\n\n        out_time[u] = ++dfs_time;\n    }\n\n  public:\n    int n;\n    vector<int> in_time, out_time;\n    vector<vector<int>> adj;\n\n    LCAUtils() : n(0) {}\n    LCAUtils(int _n) { init(_n); }\n    LCAUtils(int _n, const vector<vector<int>>& _adj, int root = 0) {\n        init(_n);\n        adj = _adj;\n        prepare(root);\n    }\n\n    void init(int _n) {\n        n = _n;\n        adj.assign(n + 1, {});\n    }\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    void prepare(int root = 1) {\n        max_log = 1;\n        while((1 << max_log) <= n) {\n            max_log++;\n        }\n\n        par_up.assign(n + 1, vector<int>(max_log));\n\n        in_time.resize(n + 1);\n        out_time.resize(n + 1);\n        dfs_time = 0;\n        dfs_lca(root, root, dfs_time);\n    }\n\n    int lca(int u, int v) {\n        if(upper(u, v)) {\n            return u;\n        }\n        if(upper(v, u)) {\n            return v;\n        }\n\n        int a = u;\n        for(int i = max_log - 1; i >= 0; i--) {\n            if(!upper(par_up[a][i], v)) {\n                a = par_up[a][i];\n            }\n        }\n\n        return par_up[a][0];\n    }\n\n    inline bool upper(int u, int v) {\n        return in_time[u] <= in_time[v] && out_time[v] <= out_time[u];\n    }\n};\n"
  },
  {
    "path": "tree/lca_sparse_table.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/data_structures/sparse_table.hpp>\nusing namespace std;\n\nclass LCAUtilsRMQ {\n  private:\n    static pair<int, int> _min_custom(pair<int, int> a, pair<int, int> b) {\n        return min(a, b);\n    }\n\n    SparseTable<pair<int, int>, _min_custom> rmq;\n    vector<int> pos, dep;\n    vector<pair<int, int>> order;\n\n    void pre_dfs(int u, int pr = -1, int d = 0) {\n        pos[u] = order.size();\n        dep[u] = d;\n        order.push_back({d, u});\n\n        for(int v: adj[u]) {\n            if(v != pr) {\n                pre_dfs(v, u, d + 1);\n                order.push_back({d, u});\n            }\n        }\n    }\n\n  public:\n    int n;\n    vector<vector<int>> adj;\n\n    LCAUtilsRMQ() { n = 0; }\n    LCAUtilsRMQ(int _n) { init(_n); }\n    LCAUtilsRMQ(int _n, const vector<vector<int>>& _adj) {\n        init(_n);\n        adj = _adj;\n    }\n\n    void add_edge(int u, int v) {\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n    }\n\n    void init(int _n) {\n        n = _n;\n        order.clear();\n        adj.assign(n, {});\n    }\n\n    void prepare(int root = 0) {\n        order.clear();\n        pos.resize(n);\n        dep.resize(n);\n        pre_dfs(root);\n        rmq.init(order);\n    }\n\n    int lca(int u, int v) {\n        if(pos[u] > pos[v]) {\n            swap(u, v);\n        }\n        return rmq.query(pos[u], pos[v]).second;\n    }\n\n    int dist(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }\n};\n\nusing LcaUtils = LCAUtilsRMQ;\n"
  },
  {
    "path": "tree/line_tree.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/graph/dsu.hpp>\n#include <coding_library/tree/lca_sparse_table.hpp>\nusing namespace std;\n\nclass LineTree {\n  private:\n    vector<vector<int>> adj;\n    LCAUtilsRMQ helper_lca;\n    vector<int> vals;\n\n    DSU uf;\n    vector<int> best_node;\n\n  public:\n    LineTree() {}\n    LineTree(\n        vector<vector<int>> _adj, vector<int> _vals, bool one_indexed = true\n    ) {\n        init(_adj, _vals, one_indexed);\n    }\n\n    void init(\n        vector<vector<int>> _adj, vector<int> _vals, bool one_indexed = true\n    ) {\n        adj = _adj;\n        vals = _vals;\n        int n = (int)vals.size() - (int)one_indexed;\n        helper_lca.init(n);\n        uf.init(n);\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), (int)one_indexed);\n        sort(perm.begin(), perm.end(), [&](int u, int v) {\n            return pair<int, int>{vals[u], u} > pair<int, int>{vals[v], v};\n        });\n\n        best_node.resize(n + 1);\n        for(int i = 1; i <= n; i++) {\n            best_node[i] = i;\n        }\n\n        for(int u: perm) {\n            for(int v: adj[u]) {\n                if(pair<int, int>{vals[v], v} > pair<int, int>{vals[u], u}) {\n                    helper_lca.add_edge(u, best_node[uf.root(v)]);\n                    uf.unite(u, v);\n                }\n            }\n\n            best_node[uf.root(u)] = u;\n        }\n\n        helper_lca.prepare(perm.back());\n    }\n\n    int min_value(int u, int v) { return vals[helper_lca.lca(u, v)]; }\n\n    int min_node(int u, int v) { return helper_lca.lca(u, v); }\n};\n"
  },
  {
    "path": "tree/link_cut_tree.hpp",
    "content": "#include <bits/stdc++.h>\nusing namespace std;\n\n// Mine was slow, so based it on maspy's implementation:\n// https://codeforces.com/contest/2097/submission/317301108\n\ntemplate<\n    class T, T (*merge)(T, T), T (*e)(), T (*inverse)(T), class G,\n    T (*lazy_apply)(G, T), G (*lazy_merge)(G, G), G (*lazy_init)(T)>\nclass LinkCutTree {\n  private:\n    const G lazy_e = lazy_init(e());\n\n    struct Node {\n        Node *left, *right, *par;\n        T value;        // Node value\n        T path_agg;     // Path aggregate\n        T subtree_agg;  // Subtree aggregate\n        G lazy;         // Lazy propagation value\n        bool flip;      // Reverse tag\n        int idx;        // Node index\n\n        Node(T val = e(), int id = -1)\n            : left(nullptr),\n              right(nullptr),\n              par(nullptr),\n              value(val),\n              path_agg(val),\n              lazy(lazy_init(e())),\n              flip(false),\n              idx(id) {}\n    };\n\n    vector<Node> nodes;\n\n    void push(Node* x) {\n        if(!x) {\n            return;\n        }\n        if(x->flip) {\n            swap(x->left, x->right);\n            if(x->left) {\n                x->left->flip = !x->left->flip;\n            }\n            if(x->right) {\n                x->right->flip = !x->right->flip;\n            }\n            x->flip = false;\n        }\n        if(x->lazy != lazy_e) {\n            x->value = lazy_apply(x->lazy, x->value);\n            x->path_agg = lazy_apply(x->lazy, x->path_agg);\n            if(x->left) {\n                x->left->lazy = lazy_merge(x->left->lazy, x->lazy);\n            }\n            if(x->right) {\n                x->right->lazy = lazy_merge(x->right->lazy, x->lazy);\n            }\n            x->lazy = lazy_e;\n        }\n    }\n\n    void pull(Node* x) {\n        if(!x) {\n            return;\n        }\n        push(x->left);\n        push(x->right);\n        x->path_agg = e();\n        if(x->left) {\n            x->path_agg = merge(x->left->path_agg, x->path_agg);\n        }\n        x->path_agg = merge(x->path_agg, x->value);\n        if(x->right) {\n            x->path_agg = merge(x->path_agg, x->right->path_agg);\n        }\n    }\n\n    inline int state(Node* n) {\n        if(!n->par) {\n            return 0;\n        }\n        if(n->par->left == n) {\n            return 1;\n        }\n        if(n->par->right == n) {\n            return -1;\n        }\n        return 0;\n    }\n\n    bool is_root(Node* x) { return state(x) == 0; }\n\n    void rotate(Node* x) {\n        Node *p = x->par, *pp = p->par;\n        if(p->left == x) {\n            p->left = x->right;\n            if(x->right) {\n                x->right->par = p;\n            }\n            x->right = p;\n        } else {\n            p->right = x->left;\n            if(x->left) {\n                x->left->par = p;\n            }\n            x->left = p;\n        }\n        p->par = x;\n        x->par = pp;\n        if(pp) {\n            if(pp->left == p) {\n                pp->left = x;\n            } else if(pp->right == p) {\n                pp->right = x;\n            } else {\n                change_light(pp, p, x);\n            }\n        }\n        pull(p);\n        pull(x);\n    }\n\n    void splay(Node* x) {\n        push(x);\n        while(!is_root(x)) {\n            Node *p = x->par, *pp = p->par;\n            if(is_root(p)) {\n                push(p);\n                push(x);\n                rotate(x);\n            } else {\n                push(pp);\n                push(p);\n                push(x);\n                if(state(x) == state(p)) {\n                    rotate(p);\n                    rotate(x);\n                } else {\n                    rotate(x);\n                    rotate(x);\n                }\n            }\n        }\n    }\n\n    Node* expose(Node* x) {\n        Node* rp = nullptr;\n        for(Node* c = x; c; c = c->par) {\n            splay(c);\n            if(c->right) {\n                add_light(c, c->right);\n            }\n            c->right = rp;\n            if(rp) {\n                erase_light(c, rp);\n            }\n            pull(c);\n            rp = c;\n        }\n        splay(x);\n        return rp;\n    }\n\n    void apply_lazy_to_node(Node* node, const G& lazy_val) {\n        if(!node) {\n            return;\n        }\n        node->lazy = lazy_merge(node->lazy, lazy_val);\n        push(node);\n    }\n\n    void add_light(Node* c, Node* light) {\n        c->subtree_agg = merge(c->subtree_agg, light->path_agg);\n    }\n\n    void erase_light(Node* c, Node* light) {\n        c->subtree_agg = merge(c->subtree_agg, inverse(light->path_agg));\n    }\n\n  public:\n    LinkCutTree(int n) : nodes(n) {\n        for(int i = 0; i < n; i++) {\n            nodes[i] = Node(e(), i);\n        }\n    }\n\n    LinkCutTree(const vector<T>& values) : nodes(values.size()) {\n        for(int i = 0; i < values.size(); i++) {\n            nodes[i] = Node(values[i], i);\n        }\n    }\n\n    Node* access(int x) {\n        Node* u = &nodes[x];\n        expose(u);\n        return u;\n    }\n\n    void reroot(int x) {\n        access(x);\n        nodes[x].flip = !nodes[x].flip;\n        push(&nodes[x]);\n    }\n\n    void link(int u, int v) {\n        reroot(u);\n        access(v);\n        assert(!nodes[u].par && !nodes[v].right);\n        nodes[u].par = &nodes[v];\n        nodes[v].right = &nodes[u];\n        pull(&nodes[v]);\n    }\n\n    void cut(int u, int v) {\n        reroot(u);\n        access(v);\n        assert(!nodes[v].par && nodes[v].left == &nodes[u]);\n        nodes[v].left->par = nullptr;\n        nodes[v].left = nullptr;\n        pull(&nodes[v]);\n    }\n\n    bool connected(int u, int v) {\n        if(u == v) {\n            return true;\n        }\n        access(u);\n        access(v);\n        return nodes[u].par != nullptr;\n    }\n\n    int lca(int u, int v) {\n        if(u == v) {\n            return u;\n        }\n        access(u);\n        Node* ancestor = expose(&nodes[v]);\n        return nodes[u].par ? ancestor->idx : -1;\n    }\n\n    T path_query(int u, int v) {\n        reroot(u);\n        access(v);\n        return nodes[v].path_agg;\n    }\n\n    void update(int u, const T& val) {\n        access(u);\n        nodes[u].value = val;\n        pull(&nodes[u]);\n    }\n\n    void path_update(int u, int v, const G& lazy_val) {\n        reroot(u);\n        access(v);\n        apply_lazy_to_node(&nodes[v], lazy_val);\n    }\n\n    T get(int u) {\n        access(u);\n        return nodes[u].value;\n    }\n\n    int get_root(int u) {\n        access(u);\n        Node* c = &nodes[u];\n        push(c);\n        while(c->left) {\n            c = c->left;\n            push(c);\n        }\n        splay(c);\n        return c->idx;\n    }\n\n    int jump(int u, int v, int k) {\n        reroot(v);\n        access(u);\n        assert(0 <= k && k < nodes[u].size);\n        Node* c = &nodes[u];\n        while(true) {\n            push(c);\n            int rs = c->right ? c->right->size : 0;\n            if(k < rs) {\n                c = c->right;\n                continue;\n            }\n            if(k == rs) {\n                break;\n            }\n            k -= (rs + 1);\n            c = c->left;\n        }\n        splay(c);\n        return c->idx;\n    }\n\n    Node* get_node(int idx) { return &nodes[idx]; }\n\n    int size() const { return nodes.size(); }\n\n    // Overload this for more complicated updates:\n    void change_light(Node* pp, Node* p, Node* x) {\n        // noop by default.\n    }\n\n    // Useful for debugging.\n    void print_node(Node* node, int indent = 0) {\n        cout << string(indent, ' ') << string(16, '-') << '\\n';\n        cout << string(indent, ' ') << \"Node \" << node->idx << \": \";\n        cout << string(indent, ' ') << \"Value: \" << node->value << '\\n';\n        cout << string(indent, ' ') << \"Path agg: \" << node->path_agg << '\\n';\n        cout << string(indent, ' ') << \"Subtree agg: \" << node->subtree_agg\n             << '\\n';\n        cout << string(indent, ' ') << \"Virtual agg: \" << node->virtual_agg\n             << '\\n';\n        cout << string(indent, ' ') << \"Lazy: \" << node->lazy.add_val << '\\n';\n        cout << string(indent, ' ') << \"HAS PARENT: \"\n             << (node->par ? to_string(node->par->idx) : \"null\") << '\\n';\n        cout << string(indent, ' ') << string(16, '-') << '\\n';\n    }\n\n    void print_tree(Node* node, int indent = 0) {\n        print_node(node, indent);\n        push(node);\n        if(node->ch[0]) {\n            cout << string(indent, ' ') << \"Left child:\\n\";\n            print_tree(node->ch[0], indent + 2);\n        }\n        if(node->ch[1]) {\n            cout << string(indent, ' ') << \"Right child:\\n\";\n            print_tree(node->ch[1], indent + 2);\n        }\n        pull(node);\n    }\n};\n"
  },
  {
    "path": "tree/vertex_add_path_sum.hpp",
    "content": "#include <bits/stdc++.h>\n#include \"coding_library/data_structures/fenwick_range_update.hpp\"\n#include \"coding_library/tree/lca.hpp\"\n\nusing namespace std;\n\nclass VertexAddPathSum : LCAUtils {\n  private:\n    FenwickRangeUpdate<int> ft;\n\n  public:\n    VertexAddPathSum() {}\n\n    void prepare(int root = 1) {\n        LCAUtils::prepare(root);\n        ft.init(dfs_time);\n    }\n\n    int query(int u, int v) {\n        int l = lca(u, v);\n        int ans =\n            ft.query(in_time[u]) + ft.query(in_time[v]) - ft.query(in_time[l]);\n        if(par_up[l][0] != l) {\n            ans -= ft.query(in_time[par_up[l][0]]);\n        }\n\n        return ans;\n    }\n\n    void update(int u, int x) { ft.update(in_time[u], out_time[u], x); }\n};\n"
  },
  {
    "path": "tree/virtual_tree.hpp",
    "content": "#include <bits/stdc++.h>\n#include <coding_library/tree/lca.hpp>\nusing namespace std;\n\nclass VirtualTree : public LCAUtils {\n  public:\n    VirtualTree() : LCAUtils() {}\n    VirtualTree(int n) : LCAUtils(n) {}\n    VirtualTree(int n, const vector<vector<int>>& adj, int root = 0)\n        : LCAUtils(n, adj, root) {\n        prepare(root);\n    }\n\n    void add_edge(int u, int v) { LCAUtils::add_edge(u, v); }\n\n    pair<vector<vector<int>>, vector<int>> build(const vector<int>& vertices) {\n        if(vertices.empty()) {\n            return {{}, {}};\n        }\n\n        vector<int> vec = vertices;\n        sort(vec.begin(), vec.end(), [&](int u, int v) {\n            return in_time[u] < in_time[v];\n        });\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n\n        for(int i = (int)vec.size() - 1; i > 0; i--) {\n            vec.push_back(lca(vec[i - 1], vec[i]));\n        }\n\n        sort(vec.begin(), vec.end(), [&](int u, int v) {\n            return in_time[u] < in_time[v];\n        });\n        vec.erase(unique(vec.begin(), vec.end()), vec.end());\n\n        vector<vector<int>> virtual_adj(vec.size());\n\n        stack<int> s;\n        s.push(0);\n        for(int i = 1; i < (int)vec.size(); i++) {\n            while(!upper(vec[s.top()], vec[i])) {\n                int u = s.top();\n                s.pop();\n                int v = s.top();\n                virtual_adj[v].push_back(u);\n            }\n            s.push(i);\n        }\n\n        while(s.size() > 1) {\n            int u = s.top();\n            s.pop();\n            int v = s.top();\n            virtual_adj[v].push_back(u);\n        }\n\n        return {virtual_adj, vec};\n    }\n};\n"
  }
]