diff --git a/docs/dynamic-tree-builder-for-vertex.md b/docs/dynamic-tree-builder-for-vertex.md index ed2d91942..0b7b1901d 100644 --- a/docs/dynamic-tree-builder-for-vertex.md +++ b/docs/dynamic-tree-builder-for-vertex.md @@ -1,6 +1,6 @@ --- title: Dynamic Tree Builder (for Vertex) -documentation_of: //structure/dynamic-tree/dynamic-tree-builder-for-edge.hpp +documentation_of: //structure/dynamic-tree/dynamic-tree-builder-for-vertex.hpp --- Link Cut Tree や Top Tree などの動的木を簡単に構築するための Builder です。 @@ -8,7 +8,7 @@ Link Cut Tree や Top Tree などの動的木を簡単に構築するための B # コンストラクタ ``` -DynamicTreeBuilderForEdge< DynamicTree, TreeDPInfo >(int n) +DynamicTreeBuilderForVertex< DynamicTree, TreeDPInfo >(int n) ``` 頂点数 `n` の動的木を作成します。各頂点に対し `set_vertex`、各辺に対し `add_edge` を呼び出したあとに、`build` を呼び出すことを期待しています。 diff --git a/docs/link-cut-tree-2.md b/docs/link-cut-tree-2.md deleted file mode 100644 index 69e8b80bd..000000000 --- a/docs/link-cut-tree-2.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -title: Link Cut Tree -documentation_of: //structure/dynamic-tree/link-cut-tree.hpp ---- - -Link Cut Tree とは動的木の一つで, 辺の追加や削除などの木構造の動的な変化がある場合でも効率的にクエリを処理できます。 - -# コンストラクタ - -``` -LinkCutTree< TreeDPInfo >() -``` - -## TreeDPInfo について - -`TreeDPInfo` は、次の構造体と関数を持つ構造体です。 - -```cpp -struct TreeDPInfo { - struct Path {}; - struct Info {}; - static Path vertex(const Info& u) {} - static Path compress(const Path& p, const Path& c) {} -}; -``` - -* `Path`: Heavy edge で繋がる頂点をまとめた結果 (Path cluster) を表す構造体 -* `Info`: 頂点を表す構造体 -* `vertex(u)`: 頂点 `u` のみからなる Path cluster を生成する関数 -* `compress(p, c)`: Path cluster `p` と `c` (`p` が根に近い側にある) をマージする関数 - -以下のコードを Splay Tree により高速化したデータ構造とみなすことができます。 - -```cpp -Path calc_heavy(int r) { - vector< Path > paths; - while(not g[r].empty()) { - paths.push_back(vertex(info[r])); - r = g[r][0]; // (r, g[r][0]) は Heavy edge - } - for(int i = 1; i < (int) paths.size(); i++) { - paths[0] = compress(paths[0], paths[i]); - } - return paths[0]; -} -``` - -# expose - -``` -NP expose(NP t) -``` - -頂点 `t` から根までのパスを Heavy edge で繋げます。`t` を Splay tree の根にして、`t` 自身を返します。 - -## 計算量 - -- amortized $O(\log n)$ - -# link - -``` -void link(NP child, NP parent) -``` - -頂点 `child` と `parent` との間に辺を追加します。 - -## 制約 - -- `child` と `parent` は異なる連結成分 -- `child` は根(根ではない場合は先に `evert(child)` を呼び出すこと) - -## 計算量 - -- amortized $O(\log n)$ - -# cut - -``` -void cut(NP child) -``` - -頂点 `child` と親との間にある辺を削除します。 - -## 制約 - -- `child` は根ではない - -## 計算量 - -- amortized $O(\log n)$ - -# evert - -``` -void evert(t) -``` - -頂点 `t` を根に変更します。 - -## 計算量 - -- amortized $O(\log n)$ - -# alloc - -``` -NP alloc(const Info &v) -``` - -Info が `v` の新しい頂点を作成します。 - -## 計算量 - -- O(1) - -# is_connected - -``` -bool is_connected(NP u, NP v) -``` - -頂点 `u` と `v` が同じ連結成分に属する場合は `true`、そうではない場合は `false` を返します。 - -関数内部で `expose(u)`、`expose(v)` の順で呼び出すため、Splay tree の木の根が変更されます。 - -## 計算量 - -- amortized $O(\log n)$ - -# build - -``` -vector build(vector &vs) -``` - -各 Info の値が `vs[i]` の新しい頂点たちを作成します。 - - -## 計算量 - -- $O(n) - -# lca - -``` -NP lca(NP u, NP v) -``` - -頂点 `u` と `v` の最小共通祖先を返します。ただし、頂点 `u` と `v` が異なる連結成分に属する場合は `nullptr` を返します。 - -関数内部で `expose(u)`、`expose(v)` の順で呼び出すため、Splay tree の木の根が変更されます。 - -## 計算量 - -- amortized $O(\log n)$ - -# set_key - -``` -void set_key(NP t, const Info &v) -``` - -頂点 `t` の Info を `v` に変更します。 - -関数内部で `expose(t)` を呼び出すため、Splay tree の木の根が `t` に変更されます。 - -## 計算量 - -- amortized $O(\log n)$ - -# query_path - -``` -(1) const Path &query_path(NP u) -(2) const Path &query_path(NP u, NP v) -``` - -1. 根から頂点 `u` までのパス上の頂点を Heavy edge で繋げ、それらを `compress` でマージした結果を返します。 -2. 頂点 `u` から頂点 `v` までのパス上の頂点を Heavy edge で繋げ、それらを `compress` でマージした結果を返します。副作用として、頂点 `u` を根に変更します。 - -## 計算量 - -- amortized $O(\log n)$ - -# find_first - -``` -pair find_first(NP u, const C &check) -``` - -根から頂点 `u` までのパス上の頂点を Heavy edge で繋げます。 - -パス上の頂点から頂点 `u` までの頂点を `compress` した結果を `path` とします。`check(path)` が `true` となるパス上の頂点のうち、頂点 `u` に最も近い頂点をその `path` とともに返します。`true` となる頂点が存在しない場合は `nullptr` を返します。 - -## 制約 - -- `check` は、第一引数に `Path`、返り値が `bool` の関数 -- `check` の結果は単調(根からある頂点まで返り値が `true` で、それ以降の頂点に対しては `false`) - -## 計算量 - -- amortized $O(\log n)$ - -## 使用例 - -頂点 `v` から `u` までのパス上に出現する頂点を並べたときに `k` 番目に現れる頂点を見つけたい場合、以下のように書けます。 - -```cpp -struct TreeDPInfo { - struct Path { int sz; }; - struct Info { int idx; }; - static Path vertex(const Info& u) { return {1}; } - static Path compress(const Path& p, const Path& c) { return {p.sz + c.sz}; } -}; - -auto res = lct.find_first(vs[u], vs[v], - [](const TreeDPInfo::Path& p) { return p.sz >= k; }); -``` diff --git a/docs/link-cut-tree-lazy-path.md b/docs/link-cut-tree-lazy-path.md deleted file mode 100644 index d9afcc561..000000000 --- a/docs/link-cut-tree-lazy-path.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -documentation_of: //structure/lct/link-cut-tree-lazy-path.hpp ---- - -## 概要 - -Link Cut Tree とは動的木の一つで, 辺の追加や削除などの木構造の動的な変化がある場合でも効率的にクエリを処理できる. - - -## 使い方 - -* `LinkCutTree(f, g, h, s, e0)`: コンストラクタ. `f` は 2 つの要素の値をマージする二項演算, `g` は要素と作用素をマージする二項演算, `h` は作用素同士をマージする二項演算, `s` は要素を反転する演算を指す. また `e0` は作用素の単位元を指す. -* `alloc(v)`: 要素の値を `v` としたノードを生成する. -* `build(vs)`: 各要素の値を `vs[i]` としたノードを生成し, その配列を返す. -* `expose(t)`: `t` と根をつなげて, `t` を splay Tree の根にする. -* `evert(t)`: `t` を根に変更する. -* `link(child, parent)`: `child` の親を `parent` にする. `child` と `parent` は別の連結成分で, `child` が根であることを要求する. -* `cut(child)`: `child` の親と `child` を切り離す. -* `is_connected(u, v)`: `u` と `v` が同じ連結成分に属する場合は `true`, そうでなければ `false` を返す. -* `lca(u, v)`: `u` と `v` の lca を返す. `u` と `v` が異なる連結成分なら `nullptr` を返す. -* `get_kth(x, k)`: `x` から根までのパスに出現するノードを並べたとき, 0-indexed で `k` 番目のノードを返す. -* `query(u)`: `u` から根までのパス上の頂点の値を二項演算でまとめた結果を返す. -* `query(u, v)`: `u` から `v` までのパス上の頂点の値を二項演算でまとめた結果を返す. -* `set_key(t, v)`: `t` の値を `v` に変更する. -* `set_propagate(t, e)`: `t` から根までのパス上の頂点に作用素 `e` を加える. -* `set_propagate(u, v, e)`: `u` から `v` までのパス上の頂点に作用素 `e` を加える. - -## 計算量 - -* 各クエリ ならし $O(\log n)$ diff --git a/docs/link-cut-tree.md b/docs/link-cut-tree.md index 7cd10648e..69e8b80bd 100644 --- a/docs/link-cut-tree.md +++ b/docs/link-cut-tree.md @@ -1,28 +1,219 @@ --- -documentation_of: //structure/lct/link-cut-tree.hpp +title: Link Cut Tree +documentation_of: //structure/dynamic-tree/link-cut-tree.hpp --- -## 概要 +Link Cut Tree とは動的木の一つで, 辺の追加や削除などの木構造の動的な変化がある場合でも効率的にクエリを処理できます。 -Link Cut Tree とは動的木の一つで, 辺の追加や削除などの木構造の動的な変化がある場合でも効率的にクエリを処理できる. +# コンストラクタ +``` +LinkCutTree< TreeDPInfo >() +``` -## 使い方 +## TreeDPInfo について -* `LinkCutTree(f, s)`: コンストラクタ. `f` は 2 つの要素の値をマージする二項演算, `s` は要素を反転する演算を指す. -* `alloc(v)`: 要素の値を `v` としたノードを生成する. -* `build(vs)`: 各要素の値を `vs[i]` としたノードを生成し, その配列を返す. -* `expose(t)`: `t` と根をつなげて, `t` を splay Tree の根にする. -* `evert(t)`: `t` を根に変更する. -* `link(child, parent)`: `child` の親を `parent` にする. `child` と `parent` は別の連結成分で, `child` が根であることを要求する. -* `cut(child)`: `child` の親と `child` を切り離す. -* `is_connected(u, v)`: `u` と `v` が同じ連結成分に属する場合は `true`, そうでなければ `false` を返す. -* `lca(u, v)`: `u` と `v` の lca を返す. `u` と `v` が異なる連結成分なら `nullptr` を返す. -* `get_kth(x, k)`: `x` から根までのパスに出現するノードを並べたとき, 0-indexed で `k` 番目のノードを返す. -* `query(u)`: `u` から根までのパス上の頂点の値を二項演算でまとめた結果を返す. -* `query(u, v)`: `u` から `v` までのパス上の頂点の値を二項演算でまとめた結果を返す. -* `set_key(t, v)`: `t` の値を `v` に変更する. +`TreeDPInfo` は、次の構造体と関数を持つ構造体です。 + +```cpp +struct TreeDPInfo { + struct Path {}; + struct Info {}; + static Path vertex(const Info& u) {} + static Path compress(const Path& p, const Path& c) {} +}; +``` + +* `Path`: Heavy edge で繋がる頂点をまとめた結果 (Path cluster) を表す構造体 +* `Info`: 頂点を表す構造体 +* `vertex(u)`: 頂点 `u` のみからなる Path cluster を生成する関数 +* `compress(p, c)`: Path cluster `p` と `c` (`p` が根に近い側にある) をマージする関数 + +以下のコードを Splay Tree により高速化したデータ構造とみなすことができます。 + +```cpp +Path calc_heavy(int r) { + vector< Path > paths; + while(not g[r].empty()) { + paths.push_back(vertex(info[r])); + r = g[r][0]; // (r, g[r][0]) は Heavy edge + } + for(int i = 1; i < (int) paths.size(); i++) { + paths[0] = compress(paths[0], paths[i]); + } + return paths[0]; +} +``` + +# expose + +``` +NP expose(NP t) +``` + +頂点 `t` から根までのパスを Heavy edge で繋げます。`t` を Splay tree の根にして、`t` 自身を返します。 + +## 計算量 + +- amortized $O(\log n)$ + +# link + +``` +void link(NP child, NP parent) +``` + +頂点 `child` と `parent` との間に辺を追加します。 + +## 制約 + +- `child` と `parent` は異なる連結成分 +- `child` は根(根ではない場合は先に `evert(child)` を呼び出すこと) + +## 計算量 + +- amortized $O(\log n)$ + +# cut + +``` +void cut(NP child) +``` + +頂点 `child` と親との間にある辺を削除します。 + +## 制約 + +- `child` は根ではない + +## 計算量 + +- amortized $O(\log n)$ + +# evert + +``` +void evert(t) +``` + +頂点 `t` を根に変更します。 + +## 計算量 + +- amortized $O(\log n)$ + +# alloc + +``` +NP alloc(const Info &v) +``` + +Info が `v` の新しい頂点を作成します。 + +## 計算量 + +- O(1) + +# is_connected + +``` +bool is_connected(NP u, NP v) +``` + +頂点 `u` と `v` が同じ連結成分に属する場合は `true`、そうではない場合は `false` を返します。 + +関数内部で `expose(u)`、`expose(v)` の順で呼び出すため、Splay tree の木の根が変更されます。 ## 計算量 -* 各クエリ ならし $O(\log n)$ +- amortized $O(\log n)$ + +# build + +``` +vector build(vector &vs) +``` + +各 Info の値が `vs[i]` の新しい頂点たちを作成します。 + + +## 計算量 + +- $O(n) + +# lca + +``` +NP lca(NP u, NP v) +``` + +頂点 `u` と `v` の最小共通祖先を返します。ただし、頂点 `u` と `v` が異なる連結成分に属する場合は `nullptr` を返します。 + +関数内部で `expose(u)`、`expose(v)` の順で呼び出すため、Splay tree の木の根が変更されます。 + +## 計算量 + +- amortized $O(\log n)$ + +# set_key + +``` +void set_key(NP t, const Info &v) +``` + +頂点 `t` の Info を `v` に変更します。 + +関数内部で `expose(t)` を呼び出すため、Splay tree の木の根が `t` に変更されます。 + +## 計算量 + +- amortized $O(\log n)$ + +# query_path + +``` +(1) const Path &query_path(NP u) +(2) const Path &query_path(NP u, NP v) +``` + +1. 根から頂点 `u` までのパス上の頂点を Heavy edge で繋げ、それらを `compress` でマージした結果を返します。 +2. 頂点 `u` から頂点 `v` までのパス上の頂点を Heavy edge で繋げ、それらを `compress` でマージした結果を返します。副作用として、頂点 `u` を根に変更します。 + +## 計算量 + +- amortized $O(\log n)$ + +# find_first + +``` +pair find_first(NP u, const C &check) +``` + +根から頂点 `u` までのパス上の頂点を Heavy edge で繋げます。 + +パス上の頂点から頂点 `u` までの頂点を `compress` した結果を `path` とします。`check(path)` が `true` となるパス上の頂点のうち、頂点 `u` に最も近い頂点をその `path` とともに返します。`true` となる頂点が存在しない場合は `nullptr` を返します。 + +## 制約 + +- `check` は、第一引数に `Path`、返り値が `bool` の関数 +- `check` の結果は単調(根からある頂点まで返り値が `true` で、それ以降の頂点に対しては `false`) + +## 計算量 + +- amortized $O(\log n)$ + +## 使用例 + +頂点 `v` から `u` までのパス上に出現する頂点を並べたときに `k` 番目に現れる頂点を見つけたい場合、以下のように書けます。 + +```cpp +struct TreeDPInfo { + struct Path { int sz; }; + struct Info { int idx; }; + static Path vertex(const Info& u) { return {1}; } + static Path compress(const Path& p, const Path& c) { return {p.sz + c.sz}; } +}; + +auto res = lct.find_first(vs[u], vs[v], + [](const TreeDPInfo::Path& p) { return p.sz >= k; }); +``` diff --git a/graph/tree/centroid-decomposition.hpp b/graph/tree/centroid-decomposition.hpp index a28982449..59ff3b140 100644 --- a/graph/tree/centroid-decomposition.hpp +++ b/graph/tree/centroid-decomposition.hpp @@ -3,7 +3,7 @@ #include "../graph-template.hpp" /** - * @brief Centroid-Decomosition(重心分解) + * @brief Centroid-Decomposition(重心分解) */ template struct CentroidDecomposition : Graph { diff --git a/other/static-point-add-rectangle-sum.hpp b/other/static-point-add-rectangle-sum.hpp index e24c418f7..d4fb36383 100644 --- a/other/static-point-add-rectangle-sum.hpp +++ b/other/static-point-add-rectangle-sum.hpp @@ -31,7 +31,7 @@ struct StaticPointAddRectangleSum { void add_point(T x, T y, C w) { points.emplace_back(Point{x, y, w}); } - // tatal weight of [l, r) * [d, u) points + // total weight of [l, r) * [d, u) points void add_query(T l, T d, T r, T u) { queries.emplace_back(Query{l, d, r, u}); } diff --git a/structure/bbst/lazy-reversible-splay-tree.hpp b/structure/bbst/lazy-reversible-splay-tree.hpp index d41c039dd..0750cc8c4 100644 --- a/structure/bbst/lazy-reversible-splay-tree.hpp +++ b/structure/bbst/lazy-reversible-splay-tree.hpp @@ -1,306 +1,90 @@ /** * @brief Lazy-Reversible-Splay-Tree(遅延伝搬反転可能Splay木) */ -template -struct LazyReversibleSplayTree { - public: - using F = function; - using G = function; - using H = function; - using S = function; - - struct Node { - Node *l, *r, *p; - Monoid key, sum; - OperatorMonoid lazy; - bool rev; - size_t sz; - - bool is_root() const { return !p || (p->l != this && p->r != this); } - - Node(const Monoid &key, const OperatorMonoid &om) - : key(key), - sum(key), - lazy(om), - sz(1), - rev(false), - l(nullptr), - r(nullptr), - p(nullptr) {} - }; - - LazyReversibleSplayTree(const F &f, const Monoid &M1) - : LazyReversibleSplayTree(f, [](const Monoid &a) { return a; }, M1) {} - - LazyReversibleSplayTree(const F &f, const S &s, const Monoid &M1) - : LazyReversibleSplayTree(f, G(), H(), s, M1, OperatorMonoid()) {} - - LazyReversibleSplayTree(const F &f, const G &g, const H &h, const S &s, - const Monoid &M1, const OperatorMonoid &OM0) - : f(f), g(g), h(h), s(s), M1(M1), OM0(OM0) {} - - inline size_t count(const Node *t) { return t ? t->sz : 0; } - - inline const Monoid &sum(const Node *t) { return t ? t->sum : M1; } - - Node *alloc(const Monoid &v = Monoid()) { return new Node(v, OM0); } - - void splay(Node *t) { - push(t); - while (!t->is_root()) { - auto *q = t->p; - if (q->is_root()) { - push(q), push(t); - if (q->l == t) - rotr(t); - else - rotl(t); - } else { - auto *r = q->p; - push(r), push(q), push(t); - if (r->l == q) { - if (q->l == t) - rotr(q), rotr(t); - else - rotl(t), rotr(t); - } else { - if (q->r == t) - rotl(q), rotl(t); - else - rotr(t), rotl(t); - } - } - } - } - - Node *push_front(Node *t, const Monoid &v = Monoid()) { - if (!t) { - t = alloc(v); - return t; - } else { - splay(t); - Node *cur = get_left(t), *z = alloc(v); - splay(cur); - z->p = cur; - cur->l = z; - splay(z); - return z; - } - } - - Node *push_back(Node *t, const Monoid &v = Monoid()) { - if (!t) { - t = alloc(v); - return t; - } else { - splay(t); - Node *cur = get_right(t), *z = alloc(v); - splay(cur); - z->p = cur; - cur->r = z; - splay(z); - return z; - } - } +template +struct LazyReversibleSplayTreeNode { + using T = Tp; + using E = Ep; + LazyReversibleSplayTreeNode *l, *r, *p; + T key, sum; + E lazy; + bool rev; + size_t sz; + + LazyReversibleSplayTreeNode() : LazyReversibleSplayTreeNode(Tp()) {} + + LazyReversibleSplayTreeNode(const T &key) + : LazyReversibleSplayTreeNode(key, E()) {} + + LazyReversibleSplayTreeNode(const T &key, const E &lazy) + : key(key), + sum(key), + rev(false), + l(nullptr), + r(nullptr), + p(nullptr), + sz(1), + lazy(lazy) {} +}; - Node *erase(Node *t) { - splay(t); - Node *x = t->l, *y = t->r; - delete t; - if (!x) { - t = y; - if (t) t->p = nullptr; - } else if (!y) { - t = x; - t->p = nullptr; - } else { - x->p = nullptr; - t = get_right(x); - splay(t); - t->r = y; - y->p = t; +template +struct LazyReversibleSplayTree : ReversibleSplayTree { + public: + public: + using Node = Np; + using T = typename Node::T; + using E = typename Node::E; + using super = ReversibleSplayTree; + using F = typename super::F; + using G = function; + using H = function; + using S = typename super::S; + using NP = typename super::NP; + + explicit LazyReversibleSplayTree(const F &f, const G &g, const H &h, + const S &s, const T &M1, const E &OM0) + : g(g), h(h), OM0(OM0), super(f, s, M1) {} + + using super::merge; + using super::splay; + using super::split; + + NP alloc(const T &x) { return new Node(x, OM0); } + + void push(NP t) override { + if (t->lazy != OM0) { + if (t->l) propagate(t->l, t->lazy); + if (t->r) propagate(t->r, t->lazy); + t->lazy = OM0; } - return t; - } - - Node *get_left(Node *t) const { - while (t->l) t = t->l; - return t; - } - - Node *get_right(Node *t) const { - while (t->r) t = t->r; - return t; + super::push(t); } - void set_propagate(Node *&t, int a, int b, const OperatorMonoid &pp) { + NP set_propagate(NP &t, int a, int b, const E &pp) { splay(t); auto x = split(t, a); auto y = split(x.second, b - a); set_propagate(y.first, pp); - t = merge(x.first, y.first, y.second); + return t = merge(x.first, y.first, y.second); } - virtual void set_propagate(Node *&t, const OperatorMonoid &pp) { + void set_propagate(NP t, const E &pp) { splay(t); propagate(t, pp); push(t); } - pair split(Node *t, int k) { - if (!t) return {nullptr, nullptr}; - push(t); - if (k <= count(t->l)) { - auto x = split(t->l, k); - t->l = x.second; - t->p = nullptr; - if (x.second) x.second->p = t; - return {x.first, update(t)}; - } else { - auto x = split(t->r, k - count(t->l) - 1); - t->r = x.first; - t->p = nullptr; - if (x.first) x.first->p = t; - return {update(t), x.second}; - } - } - - tuple split3(Node *t, int a, int b) { - splay(t); - auto x = split(t, a); - auto y = split(x.second, b - a); - return make_tuple(x.first, y.first, y.second); - } - - template - Node *merge(Node *l, Args... rest) { - Node *r = merge(rest...); - if (!l && !r) return nullptr; - if (!l) return splay(r), r; - if (!r) return splay(l), l; - splay(l), splay(r); - l = get_right(l); - splay(l); - l->r = r; - r->p = l; - update(l); - return l; - } - - void insert(Node *&t, int k, const Monoid &v) { - splay(t); - auto x = split(t, k); - t = merge(x.first, alloc(v), x.second); - } - - Monoid erase(Node *&t, int k) { - splay(t); - auto x = split(t, k); - auto y = split(x.second, 1); - auto v = y.first->c; - delete y.first; - t = merge(x.first, y.second); - return v; - } - - Monoid query(Node *&t, int a, int b) { - splay(t); - auto x = split(t, a); - auto y = split(x.second, b - a); - auto ret = sum(y.first); - t = merge(x.first, y.first, y.second); - return ret; - } - - Node *build(const vector &v) { return build(0, (int)v.size(), v); } - - void toggle(Node *t) { - swap(t->l, t->r); - t->sum = s(t->sum); - t->rev ^= true; - } - - Node *update(Node *t) { - t->sz = 1; - t->sum = t->key; - if (t->l) t->sz += t->l->sz, t->sum = f(t->l->sum, t->sum); - if (t->r) t->sz += t->r->sz, t->sum = f(t->sum, t->r->sum); - return t; - } - - void push(Node *t) { - if (t->lazy != OM0) { - if (t->l) propagate(t->l, t->lazy); - if (t->r) propagate(t->r, t->lazy); - t->lazy = OM0; - } - if (t->rev) { - if (t->l) toggle(t->l); - if (t->r) toggle(t->r); - t->rev = false; - } - } - - void set_element(Node *&t, int k, const Monoid &x) { - splay(t); - sub_set_element(t, k, x); - } - private: - const Monoid M1; - const OperatorMonoid OM0; - const F f; + const E OM0; const G g; const H h; - const S s; - - Node *build(int l, int r, const vector &v) { - if (l + 1 >= r) return alloc(v[l]); - return merge(build(l, (l + r) >> 1, v), build((l + r) >> 1, r, v)); - } - void propagate(Node *t, const OperatorMonoid &x) { + void propagate(NP t, const E &x) { t->lazy = h(t->lazy, x); t->key = g(t->key, x); t->sum = g(t->sum, x); } - - void rotr(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->l = t->r)) t->r->p = x; - t->r = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); - } - } - - void rotl(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->r = t->l)) t->l->p = x; - t->l = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); - } - } - - Node *merge(Node *l) { return l; } - - Node *sub_set_element(Node *&t, int k, const Monoid &x) { - push(t); - if (k < count(t->l)) { - return sub_set_element(t->l, k, x); - } else if (k == count(t->l)) { - t->key = x; - splay(t); - return t; - } else { - return sub_set_element(t->r, k - count(t->l) - 1, x); - } - } }; + +template +using LRST = LazyReversibleSplayTree >; diff --git a/structure/bbst/reversible-splay-tree.hpp b/structure/bbst/reversible-splay-tree.hpp index b334638c8..a85a4287e 100644 --- a/structure/bbst/reversible-splay-tree.hpp +++ b/structure/bbst/reversible-splay-tree.hpp @@ -1,180 +1,51 @@ /** * @brief Reversible-Splay-Tree(反転可能Splay木) */ -template -struct ReversibleSplayTree { - public: - using F = function; - using S = function; - - struct Node { - Node *l, *r, *p; - Monoid key, sum; - bool rev; - size_t sz; - - bool is_root() const { return !p || (p->l != this && p->r != this); } - - Node(const Monoid &key) - : key(key), - sum(key), - sz(1), - rev(false), - l(nullptr), - r(nullptr), - p(nullptr) {} - }; - - ReversibleSplayTree(const F &f, const Monoid &M1) - : ReversibleSplayTree(f, [](const Monoid &a) { return a; }, M1) {} +template +struct ReversibleSplayTreeNode { + using T = Tp; + ReversibleSplayTreeNode *l, *r, *p; + T key, sum; + bool rev; + size_t sz; + + ReversibleSplayTreeNode() : ReversibleSplayTreeNode(Tp()) {} + + ReversibleSplayTreeNode(const T &key) + : key(key), + sum(key), + rev(false), + l(nullptr), + r(nullptr), + p(nullptr), + sz(1) {} +}; - ReversibleSplayTree(const F &f, const S &s, const Monoid &M1) +template +struct ReversibleSplayTree : SplayTreeBase { + public: + using Node = Np; + using T = typename Node::T; + using F = function; + using S = function; + using super = SplayTreeBase; + using NP = typename super::NP; + + explicit ReversibleSplayTree(const F &f, const S &s, const T &M1) : f(f), s(s), M1(M1) {} - inline size_t count(const Node *t) { return t ? t->sz : 0; } - - inline const Monoid &sum(const Node *t) { return t ? t->sum : M1; } - - Node *alloc(const Monoid &v = Monoid()) { return new Node(v); } - - void splay(Node *t) { - push(t); - while (!t->is_root()) { - auto *q = t->p; - if (q->is_root()) { - push(q), push(t); - if (q->l == t) - rotr(t); - else - rotl(t); - } else { - auto *r = q->p; - push(r), push(q), push(t); - if (r->l == q) { - if (q->l == t) - rotr(q), rotr(t); - else - rotl(t), rotr(t); - } else { - if (q->r == t) - rotl(q), rotl(t); - else - rotr(t), rotl(t); - } - } - } - } - - Node *push_front(Node *t, const Monoid &v = Monoid()) { - if (!t) { - t = alloc(v); - return t; - } else { - splay(t); - Node *cur = get_left(t), *z = alloc(v); - splay(cur); - z->p = cur; - cur->l = z; - splay(z); - return z; - } - } - - Node *push_back(Node *t, const Monoid &v = Monoid()) { - if (!t) { - t = alloc(v); - return t; - } else { - splay(t); - Node *cur = get_right(t), *z = alloc(v); - splay(cur); - z->p = cur; - cur->r = z; - splay(z); - return z; - } - } - - Node *erase(Node *t) { - splay(t); - Node *x = t->l, *y = t->r; - delete t; - if (!x) { - t = y; - if (t) t->p = nullptr; - } else if (!y) { - t = x; - t->p = nullptr; - } else { - x->p = nullptr; - t = get_right(x); - splay(t); - t->r = y; - y->p = t; - } - return t; - } - - Node *get_left(Node *t) const { - while (t->l) t = t->l; - return t; - } - - Node *get_right(Node *t) const { - while (t->r) t = t->r; - return t; - } - - pair split(Node *t, int k) { - if (!t) return {nullptr, nullptr}; - push(t); - if (k <= count(t->l)) { - auto x = split(t->l, k); - t->l = x.second; - t->p = nullptr; - if (x.second) x.second->p = t; - return {x.first, update(t)}; - } else { - auto x = split(t->r, k - count(t->l) - 1); - t->r = x.first; - t->p = nullptr; - if (x.first) x.first->p = t; - return {update(t), x.second}; - } - } - - template - Node *merge(Node *l, Args... rest) { - Node *r = merge(rest...); - if (!l && !r) return nullptr; - if (!l) return splay(r), r; - if (!r) return splay(l), l; - splay(l), splay(r); - l = get_right(l); - splay(l); - l->r = r; - r->p = l; - update(l); - return l; - } + using super::build_node; + using super::count; + using super::insert_node; + using super::merge; + using super::splay; + using super::split; - void insert(Node *&t, int k, const Monoid &v) { - splay(t); - auto x = split(t, k); - t = merge(merge(x.first, alloc(v)), x.second); - } + inline const T &sum(const NP t) { return t ? t->sum : M1; } - Monoid erase(Node *&t, int k) { - splay(t); - auto x = split(t, k); - auto y = split(x.second, 1); - auto v = y.first->c; - delete y.first; - t = merge(x.first, y.second); - return v; - } + NP alloc(const T &x) { return new Node(x); } - Monoid query(Node *&t, int a, int b) { + T query(NP &t, int a, int b) { splay(t); auto x = split(t, a); auto y = split(x.second, b - a); @@ -183,15 +54,19 @@ struct ReversibleSplayTree { return ret; } - Node *build(const vector &v) { return build(0, (int)v.size(), v); } + NP build(const vector &v) { + vector vs(v.size()); + for (int i = 0; i < v.size(); i++) vs[i] = alloc(v[i]); + return build_node(vs); + } - void toggle(Node *t) { + void toggle(NP t) { swap(t->l, t->r); t->sum = s(t->sum); t->rev ^= true; } - Node *update(Node *t) { + NP update(NP t) override { t->sz = 1; t->sum = t->key; if (t->l) t->sz += t->l->sz, t->sum = f(t->l->sum, t->sum); @@ -199,14 +74,7 @@ struct ReversibleSplayTree { return t; } - tuple split3(Node *t, int a, int b) { - splay(t); - auto x = split(t, a); - auto y = split(x.second, b - a); - return make_tuple(x.first, y.first, y.second); - } - - void push(Node *t) { + void push(NP t) override { if (t->rev) { if (t->l) toggle(t->l); if (t->r) toggle(t->r); @@ -214,57 +82,49 @@ struct ReversibleSplayTree { } } - void set_element(Node *&t, int k, const Monoid &x) { + NP insert(NP t, int k, const T &x) { return insert_node(t, k, alloc(x)); } + + NP set_element(NP t, int k, const T &x) { splay(t); - sub_set_element(t, k, x); + return imp_set_element(t, k, x); + } + + pair split_lower_bound(NP t, const T &key) { + if (!t) return {nullptr, nullptr}; + push(t); + if (key <= t->key) { + auto x = split_lower_bound(t->l, key); + t->l = x.second; + t->p = nullptr; + if (x.second) x.second->p = t; + return {x.first, update(t)}; + } else { + auto x = split_lower_bound(t->r, key); + t->r = x.first; + t->p = nullptr; + if (x.first) x.first->p = t; + return {update(t), x.second}; + } } private: - const Monoid M1; + const T M1; const F f; const S s; - Node *build(int l, int r, const vector &v) { - if (l + 1 >= r) return alloc(v[l]); - return merge(build(l, (l + r) >> 1, v), build((l + r) >> 1, r, v)); - } - - Node *sub_set_element(Node *&t, int k, const Monoid &x) { + NP imp_set_element(NP t, int k, const T &x) { push(t); if (k < count(t->l)) { - return sub_set_element(t->l, k, x); + return imp_set_element(t->l, k, x); } else if (k == count(t->l)) { t->key = x; splay(t); return t; } else { - return sub_set_element(t->r, k - count(t->l) - 1, x); - } - } - - void rotr(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->l = t->r)) t->r->p = x; - t->r = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); + return imp_set_element(t->r, k - count(t->l) - 1, x); } } - - void rotl(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->r = t->l)) t->l->p = x; - t->l = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); - } - } - - Node *merge(Node *l) { return l; } }; + +template +using RST = ReversibleSplayTree >; diff --git a/structure/develop/splay-tree-base.hpp b/structure/bbst/splay-tree-base.hpp similarity index 100% rename from structure/develop/splay-tree-base.hpp rename to structure/bbst/splay-tree-base.hpp diff --git a/structure/develop/array-pool.hpp b/structure/develop/array-pool.hpp deleted file mode 100644 index f07b816f2..000000000 --- a/structure/develop/array-pool.hpp +++ /dev/null @@ -1,17 +0,0 @@ -template -struct ArrayPool { - array pool; - array stock; - int ptr; - - ArrayPool() { clear(); } - - inline T *alloc() { return stock[--ptr]; } - - inline void free(T *t) { stock[ptr++] = t; } - - void clear() { - ptr = (int)pool.size(); - for (int i = 0; i < pool.size(); i++) stock[i] = &pool[i]; - } -}; diff --git a/structure/develop/diameter.hpp b/structure/develop/diameter.hpp deleted file mode 100644 index 1a509e05f..000000000 --- a/structure/develop/diameter.hpp +++ /dev/null @@ -1,92 +0,0 @@ -#include "super-link-cut-tree.hpp" - -/** - * @brief Diameter - */ -using T = int64_t; - -// 遅延伝搬をするための作用素 -struct Lazy { - // 単位元 - Lazy() {} - - // 初期化 - Lazy(T v) {} - - // 遅延伝搬 - void propagate(const Lazy &p) {} -}; - -// Light-edge の情報 -template -struct LInfo { - T dia, dep; - - T dia_max, dep_max, dep_max2; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - LInfo() : dia_max(-infll), dep_max(-infll), dep_max2(-infll) {} - - // 初期化 - LInfo(T dia, T dep) : dia(dia), dep(dep) {} - - // l, r は Splay-tree の子 (原理上、各ノード区別はない) - void update(const LInfo &l, const LInfo &r) { - dia_max = max({l.dia_max, r.dia_max, dia}); - if (dep < l.dep_max) { - dep_max2 = max(l.dep_max2, dep); - dep_max = l.dep_max; - } else { - dep_max2 = l.dep_max; - dep_max = dep; - } - if (dep_max < r.dep_max) { - dep_max2 = max(dep_max, r.dep_max2); - dep_max = r.dep_max; - } else { - dep_max2 = max(dep_max2, r.dep_max); - } - } - - // 部分木への遅延伝搬 - void propagate(const Lazy &p) {} -}; - -// Heavy-edge の情報 -template -struct Info { - T cost; - - T dia_max, p_len, c_len, all; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - Info() : dia_max(0), p_len(0), c_len(0), all(0) {} - - // 初期化 - Info(T v) : cost(v) {} - - // 反転 - void toggle() { swap(p_len, c_len); } - - // pが親, cがheavy-edgeで結ばれた子, lがそれ以外の子 - void update(const Info &p, const Info &c, const LInfo &l) { - all = p.all + cost + c.all; - p_len = max({p.p_len, p.all + cost + max(l.dep_max, c.p_len)}); - c_len = max({c.c_len, c.all + cost + max(l.dep_max, p.c_len)}); - dia_max = max( - {p.dia_max, c.dia_max, l.dia_max, l.dep_max + cost + l.dep_max2, - p.c_len + cost + max(l.dep_max, c.p_len), l.dep_max + cost + c.p_len}); - } - - // 親と light-edge で繋げる - LInfo link() const { return LInfo(dia_max, p_len); } - - // 遅延伝搬 - void propagate(const Lazy &p) {} - - // light-edgeに対する遅延伝搬 - // pathとsubtreeの遅延伝搬が両方ある場合に実装する - void propagate_light(const Lazy &p) {} -}; - -using LCT = SuperLinkCutTree; diff --git a/structure/develop/dynamic-tree-test.hpp b/structure/develop/dynamic-tree-test.hpp deleted file mode 100644 index bfebee80a..000000000 --- a/structure/develop/dynamic-tree-test.hpp +++ /dev/null @@ -1,156 +0,0 @@ -#include "super-link-cut-tree.hpp" - -/** - * @brief Dynamic Tree Test - * @see https://dmoj.ca/problem/ds5 - */ -using T = int; -const T inf_max = numeric_limits::max(); -const T inf_min = numeric_limits::min(); - -// 遅延伝搬をする作用素 -struct Lazy { - int type; // 0: none, 1: change, 2:inc - T v; - - // 単位元 - Lazy() : type(0) {} - - // 初期化 - constexpr Lazy(int type, T v) : type(type), v(v) {} - - inline constexpr void propagate(const Lazy &p) { - if (p.type == 0) { - return; - } - if (type == 0 or p.type == 1) { - type = p.type; - v = p.v; - } else { - v += p.v; - } - } -}; - -// Light-edge の情報 -template -struct LInfo { - T min, max, sum, sz; - - T all_min, all_max, all_sum, all_sz; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - LInfo() : all_min(inf_max), all_max(inf_min), all_sum(0), all_sz(0) {} - - // 初期化 - LInfo(T min, T max, T sum, T sz) : min(min), max(max), sum(sum), sz(sz) {} - - // l, r は Splay-tree の子 (原理上、各ノード区別はない) - void update(const LInfo &l, const LInfo &r) { - all_min = std::min({l.all_min, min, r.all_min}); - all_max = std::max({l.all_max, max, r.all_max}); - all_sum = l.all_sum + sum + r.all_sum; - all_sz = l.all_sz + sz + r.all_sz; - } - - // light-edgeに対する遅延伝搬 - void propagate(const Lazy &p) { - if (p.type == 0) { - return; - } else if (p.type == 1) { // change - min = p.v; - max = p.v; - sum = p.v * sz; - all_min = p.v; - all_max = p.v; - all_sum = p.v * all_sz; - } else { // inc - min += p.v; - max += p.v; - sum += p.v * sz; - all_min += p.v; - all_max += p.v; - all_sum += p.v * all_sz; - } - } -}; - -// Heavy-edge の情報 -template -struct Info { - T v; - - T path_min, path_max, path_sum, path_sz; - T light_min, light_max, light_sum, light_sz; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - Info() - : light_min(inf_max), - light_max(inf_min), - light_sum(0), - light_sz(0), - path_min(inf_max), - path_max(inf_min), - path_sum(0), - path_sz(0) {} - - // 初期化 - Info(T v) : v(v) {} - - // 反転 - void toggle() {} - - // pが親, cがheavy-edgeで結ばれた子, lがそれ以外の子 - void update(const Info &p, const Info &c, const LInfo &l) { - light_min = min({p.light_min, c.light_min, l.all_min}); - light_max = max({p.light_max, c.light_max, l.all_max}); - light_sum = p.light_sum + c.light_sum + l.all_sum; - light_sz = p.light_sz + c.light_sz + l.all_sz; - - path_min = min({p.path_min, v, c.path_min}); - path_max = max({p.path_max, v, c.path_max}); - path_sum = p.path_sum + v + c.path_sum; - path_sz = p.path_sz + 1 + c.path_sz; - } - - // 親と light-edge で繋げる - LInfo link() const { - return LInfo(min(light_min, path_min), max(light_max, path_max), - path_sum + light_sum, light_sz + path_sz); - } - - // 遅延伝搬 - void propagate(const Lazy &p) { - if (p.type == 0) { - return; - } else if (p.type == 1) { // change - v = p.v; - path_min = p.v; - path_max = p.v; - path_sum = p.v * path_sz; - } else { // inc - v += p.v; - path_min += p.v; - path_max += p.v; - path_sum += p.v * path_sz; - } - } - - // light-edgeに対する遅延伝搬 - // pathとsubtreeの遅延伝搬が両方ある場合に実装する - void propagate_light(const Lazy &p) { - if (p.type == 0 or light_min == inf_max) { - return; - } else if (p.type == 1) { // change - light_min = p.v; - light_max = p.v; - light_sum = p.v * light_sz; - } else { // inc - light_min += p.v; - light_max += p.v; - light_sum += p.v * light_sz; - } - } -}; - -using LCT = SuperLinkCutTree; diff --git a/structure/develop/lazy-reversible-splay-tree.hpp b/structure/develop/lazy-reversible-splay-tree.hpp deleted file mode 100644 index 0750cc8c4..000000000 --- a/structure/develop/lazy-reversible-splay-tree.hpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * @brief Lazy-Reversible-Splay-Tree(遅延伝搬反転可能Splay木) - */ -template -struct LazyReversibleSplayTreeNode { - using T = Tp; - using E = Ep; - LazyReversibleSplayTreeNode *l, *r, *p; - T key, sum; - E lazy; - bool rev; - size_t sz; - - LazyReversibleSplayTreeNode() : LazyReversibleSplayTreeNode(Tp()) {} - - LazyReversibleSplayTreeNode(const T &key) - : LazyReversibleSplayTreeNode(key, E()) {} - - LazyReversibleSplayTreeNode(const T &key, const E &lazy) - : key(key), - sum(key), - rev(false), - l(nullptr), - r(nullptr), - p(nullptr), - sz(1), - lazy(lazy) {} -}; - -template -struct LazyReversibleSplayTree : ReversibleSplayTree { - public: - public: - using Node = Np; - using T = typename Node::T; - using E = typename Node::E; - using super = ReversibleSplayTree; - using F = typename super::F; - using G = function; - using H = function; - using S = typename super::S; - using NP = typename super::NP; - - explicit LazyReversibleSplayTree(const F &f, const G &g, const H &h, - const S &s, const T &M1, const E &OM0) - : g(g), h(h), OM0(OM0), super(f, s, M1) {} - - using super::merge; - using super::splay; - using super::split; - - NP alloc(const T &x) { return new Node(x, OM0); } - - void push(NP t) override { - if (t->lazy != OM0) { - if (t->l) propagate(t->l, t->lazy); - if (t->r) propagate(t->r, t->lazy); - t->lazy = OM0; - } - super::push(t); - } - - NP set_propagate(NP &t, int a, int b, const E &pp) { - splay(t); - auto x = split(t, a); - auto y = split(x.second, b - a); - set_propagate(y.first, pp); - return t = merge(x.first, y.first, y.second); - } - - void set_propagate(NP t, const E &pp) { - splay(t); - propagate(t, pp); - push(t); - } - - private: - const E OM0; - const G g; - const H h; - - void propagate(NP t, const E &x) { - t->lazy = h(t->lazy, x); - t->key = g(t->key, x); - t->sum = g(t->sum, x); - } -}; - -template -using LRST = LazyReversibleSplayTree >; diff --git a/structure/develop/link-cut-tree.hpp b/structure/develop/link-cut-tree.hpp deleted file mode 100644 index 758eed344..000000000 --- a/structure/develop/link-cut-tree.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/** - * @brief Link-Cut-Tree - */ -template -struct LinkCutTree : STp { - using ST = STp; - using ST::ST; - using Node = typename ST::Node; - - Node *expose(Node *t) { - Node *rp = nullptr; - for (Node *cur = t; cur; cur = cur->p) { - this->splay(cur); - cur->r = rp; - this->update(cur); - rp = cur; - } - this->splay(t); - return rp; - } - - void link(Node *child, Node *parent) { - expose(child); - expose(parent); - child->p = parent; - parent->r = child; - this->update(parent); - } - - void cut(Node *child) { - expose(child); - auto *parent = child->l; - child->l = nullptr; - parent->p = nullptr; - this->update(child); - } - - void evert(Node *t) { - expose(t); - this->toggle(t); - this->push(t); - } - - Node *lca(Node *u, Node *v) { - if (get_root(u) != get_root(v)) return nullptr; - expose(u); - return expose(v); - } - - Node *get_kth(Node *x, int k) { - expose(x); - while (x) { - this->push(x); - if (x->r && x->r->sz > k) { - x = x->r; - } else { - if (x->r) k -= x->r->sz; - if (k == 0) return x; - k -= 1; - x = x->l; - } - } - return nullptr; - } - - Node *get_root(Node *x) { - expose(x); - while (x->l) { - this->push(x); - x = x->l; - } - return x; - } -}; diff --git a/structure/develop/reversible-splay-tree.hpp b/structure/develop/reversible-splay-tree.hpp deleted file mode 100644 index a85a4287e..000000000 --- a/structure/develop/reversible-splay-tree.hpp +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @brief Reversible-Splay-Tree(反転可能Splay木) - */ -template -struct ReversibleSplayTreeNode { - using T = Tp; - ReversibleSplayTreeNode *l, *r, *p; - T key, sum; - bool rev; - size_t sz; - - ReversibleSplayTreeNode() : ReversibleSplayTreeNode(Tp()) {} - - ReversibleSplayTreeNode(const T &key) - : key(key), - sum(key), - rev(false), - l(nullptr), - r(nullptr), - p(nullptr), - sz(1) {} -}; - -template -struct ReversibleSplayTree : SplayTreeBase { - public: - using Node = Np; - using T = typename Node::T; - using F = function; - using S = function; - using super = SplayTreeBase; - using NP = typename super::NP; - - explicit ReversibleSplayTree(const F &f, const S &s, const T &M1) - : f(f), s(s), M1(M1) {} - - using super::build_node; - using super::count; - using super::insert_node; - using super::merge; - using super::splay; - using super::split; - - inline const T &sum(const NP t) { return t ? t->sum : M1; } - - NP alloc(const T &x) { return new Node(x); } - - T query(NP &t, int a, int b) { - splay(t); - auto x = split(t, a); - auto y = split(x.second, b - a); - auto ret = sum(y.first); - t = merge(x.first, y.first, y.second); - return ret; - } - - NP build(const vector &v) { - vector vs(v.size()); - for (int i = 0; i < v.size(); i++) vs[i] = alloc(v[i]); - return build_node(vs); - } - - void toggle(NP t) { - swap(t->l, t->r); - t->sum = s(t->sum); - t->rev ^= true; - } - - NP update(NP t) override { - t->sz = 1; - t->sum = t->key; - if (t->l) t->sz += t->l->sz, t->sum = f(t->l->sum, t->sum); - if (t->r) t->sz += t->r->sz, t->sum = f(t->sum, t->r->sum); - return t; - } - - void push(NP t) override { - if (t->rev) { - if (t->l) toggle(t->l); - if (t->r) toggle(t->r); - t->rev = false; - } - } - - NP insert(NP t, int k, const T &x) { return insert_node(t, k, alloc(x)); } - - NP set_element(NP t, int k, const T &x) { - splay(t); - return imp_set_element(t, k, x); - } - - pair split_lower_bound(NP t, const T &key) { - if (!t) return {nullptr, nullptr}; - push(t); - if (key <= t->key) { - auto x = split_lower_bound(t->l, key); - t->l = x.second; - t->p = nullptr; - if (x.second) x.second->p = t; - return {x.first, update(t)}; - } else { - auto x = split_lower_bound(t->r, key); - t->r = x.first; - t->p = nullptr; - if (x.first) x.first->p = t; - return {update(t), x.second}; - } - } - - private: - const T M1; - const F f; - const S s; - - NP imp_set_element(NP t, int k, const T &x) { - push(t); - if (k < count(t->l)) { - return imp_set_element(t->l, k, x); - } else if (k == count(t->l)) { - t->key = x; - splay(t); - return t; - } else { - return imp_set_element(t->r, k - count(t->l) - 1, x); - } - } -}; - -template -using RST = ReversibleSplayTree >; diff --git a/structure/develop/splay-tree.hpp b/structure/develop/splay-tree.hpp deleted file mode 100644 index c324d8ea9..000000000 --- a/structure/develop/splay-tree.hpp +++ /dev/null @@ -1,123 +0,0 @@ -template -struct SplayTree { - const key_t e; - - SplayTree() : pool(), e(key_t()) {} - - struct Node { - Node *l, *r, *p; - key_t sum; - - Node() = default; - - explicit Node(const key_t &k) - : sum(k), l(nullptr), r(nullptr), p(nullptr) {} - }; - - ArrayPool pool; - - private: - void rotr(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->l = t->r)) t->r->p = x; - t->r = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); - } - } - - void rotl(Node *t) { - auto *x = t->p, *y = x->p; - if ((x->r = t->l)) t->l->p = x; - t->l = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - update(y); - } - } - - void update(Node *t) { - t->sum.set_sum(); - if (t->l) t->sum.update(t->l->sum); - if (t->r) t->sum.update(t->r->sum); - } - - Node *get_right(Node *t) const { - while (t->r) t = t->r; - return t; - } - - inline Node *alloc(const key_t &v) { - auto p = &(*pool.alloc() = Node(v)); - update(p); - return p; - } - - void splay(Node *t) { - while (t->p) { - auto *q = t->p; - if (!q->p) { - if (q->l == t) - rotr(t); - else - rotl(t); - } else { - auto *r = q->p; - if (r->l == q) { - if (q->l == t) - rotr(q), rotr(t); - else - rotl(t), rotr(t); - } else { - if (q->r == t) - rotl(q), rotl(t); - else - rotr(t), rotl(t); - } - } - } - } - - public: - inline const key_t &sum(Node *t) { return t ? t->sum : e; } - - Node *push_back(Node *t, const key_t &v) { - if (!t) { - t = alloc(v); - return t; - } else { - Node *cur = get_right(t), *z = alloc(v); - z->p = cur; - cur->r = z; - update(cur); - splay(z); - return z; - } - } - - Node *erase(Node *t) { - splay(t); - Node *x = t->l, *y = t->r; - pool.free(t); - if (!x) { - t = y; - if (t) t->p = nullptr; - } else if (!y) { - t = x; - t->p = nullptr; - } else { - x->p = nullptr; - t = get_right(x); - splay(t); - t->r = y; - y->p = t; - update(t); - } - return t; - } -}; diff --git a/structure/develop/subtree-add-subtree-sum.hpp b/structure/develop/subtree-add-subtree-sum.hpp deleted file mode 100644 index 9d55fd70c..000000000 --- a/structure/develop/subtree-add-subtree-sum.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "super-link-cut-tree.hpp" - -/** - * @brief Subtree Add Subtree Sum - */ -using T = int64_t; - -// 全体への遅延伝搬をするための作用素 -struct Lazy { - T v; - - // 単位元 - Lazy() : v{0} {} - - // 初期化 - Lazy(T v) : v{v} {} - - void propagate(const Lazy &p) { v += p.v; } -}; - -// Light-edge の情報 -template -struct LInfo { - T sum; - int sz; - - T sum_sum; - int sz_sum; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - LInfo() : sum_sum{0}, sz_sum{0} {} - - // 初期化 - LInfo(T sum, int sz) : sum{sum}, sz{sz} {} - - // l, r は Splay-tree の子 (原理上、各ノード区別はない) - void update(const LInfo &l, const LInfo &r) { - sum_sum = l.sum_sum + sum + r.sum_sum; - sz_sum = l.sz_sum + sz + r.sz_sum; - } - - // 部分木への遅延伝搬 - void propagate(const Lazy &p) { - sum_sum += sz_sum * p.v; - sum += sz * p.v; - } -}; - -// Heavy-edge の情報 -template -struct Info { - T sum; - - T sum_sum; - int sz_sum; - - // 単位元(キーの値はアクセスしないので未初期化でもよい - Info() : sum_sum{0}, sz_sum{0} {} - - // 初期化 - Info(T sum) : sum{sum} {} - - // 反転 - void toggle() {} - - // pが親, cがheavy-edgeで結ばれた子, lがそれ以外の子 - void update(const Info &p, const Info &c, const LInfo &l) { - sum_sum = p.sum_sum + sum + (c.sum_sum + l.sum_sum); - sz_sum = p.sz_sum + 1 + (c.sz_sum + l.sz_sum); - } - - // 親と light-edge で繋げる - LInfo link() const { return LInfo(sum_sum, sz_sum); } - - // 遅延伝搬 - void propagate(const Lazy &p) { - sum_sum += p.v * sz_sum; - sum += p.v; - } - - // light-edgeに対する遅延伝搬 - // pathとsubtreeの遅延伝搬が両方ある場合に実装する - void propagate_light(const Lazy &p) {} -}; - -using LCT = SuperLinkCutTree; diff --git a/structure/develop/super-link-cut-tree.hpp b/structure/develop/super-link-cut-tree.hpp deleted file mode 100644 index 71c19e2c8..000000000 --- a/structure/develop/super-link-cut-tree.hpp +++ /dev/null @@ -1,483 +0,0 @@ -/** - * @brief 何でもできるLCT - */ -template -struct SplayTree { - struct Node { - Node *l, *r, *p; - LInfo info; - Lazy lazy, lbuf; - - explicit Node(const LInfo &info) - : info(info), - l(nullptr), - r(nullptr), - p(nullptr), - lazy(Lazy()), - lbuf(Lazy()) {} - }; - - const LInfo e; - - SplayTree() : e(LInfo()) {} - - using NP = Node *; - - void rotr(NP t) { - NP x = t->p, y = x->p; - push(x), push(t); - if ((x->l = t->r)) t->r->p = x; - t->r = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - } - } - - void rotl(NP t) { - NP x = t->p, y = x->p; - push(x), push(t); - if ((x->r = t->l)) t->l->p = x; - t->l = x, x->p = t; - update(x), update(t); - if ((t->p = y)) { - if (y->l == x) y->l = t; - if (y->r == x) y->r = t; - } - } - - const LInfo &get_info(NP t) { return t ? t->info : e; } - - void update(NP t) { t->info.update(get_info(t->l), get_info(t->r)); } - - NP get_right(NP t) { - while (t->r) t = t->r; - return t; - } - - NP alloc(const LInfo &v) { - auto t = new Node(v); - update(t); - return t; - } - - void propagate(NP t, const Lazy &lazy) { - t->info.propagate(lazy); - t->lbuf.propagate(lazy); - t->lazy.propagate(lazy); - } - - void push(NP t) { - if (t->l) propagate(t->l, t->lazy); - if (t->r) propagate(t->r, t->lazy); - t->lazy = Lazy(); - } - - void splay(NP t) { - push(t); - while (t->p) { - NP q = t->p; - if (!q->p) { - if (q->l == t) - rotr(t); - else - rotl(t); - } else { - NP r = q->p; - if (r->l == q) { - if (q->l == t) - rotr(q), rotr(t); - else - rotl(t), rotr(t); - } else { - if (q->r == t) - rotl(q), rotl(t); - else - rotr(t), rotl(t); - } - } - } - } - - NP insert(NP t, const LInfo &v) { - if (not t) { - t = alloc(v); - return t; - } else { - NP cur = get_right(t), z = alloc(v); - splay(cur); - z->p = cur; - cur->r = z; - update(cur); - splay(z); - return z; - } - } - - NP erase(NP t) { - splay(t); - NP x = t->l, y = t->r; - delete t; - if (not x) { - t = y; - if (t) t->p = nullptr; - } else if (not y) { - t = x; - t->p = nullptr; - } else { - x->p = nullptr; - t = get_right(x); - splay(t); - t->r = y; - y->p = t; - update(t); - } - return t; - } -}; - -template