This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub suisen-cp/cp-library-cpp
#include "library/tree/static_top_tree.hpp"
#ifndef SUISEN_STATIC_TOP_TREE_HPP #define SUISEN_STATIC_TOP_TREE_HPP #include <cassert> #include <vector> namespace suisen { struct static_toptree { private: enum class NodeTag { VERTEX, ADD_EDGE, MERGE_SUBTREES, ADD_ROOT, MERGE_PATHS, }; struct Node { NodeTag tag; int ch_id[2]{ -1, -1 }; int par_id = -1; int v; Node(NodeTag tag, int lch, int rch, int v) : tag(tag), ch_id{ lch, rch }, v(v) {} static int vertex(int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::VERTEX, -1, -1, v); return id; } static int add_edge(int ch, int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::ADD_EDGE, ch, -1, v); return id; } static int merge_subtrees(int lch, int rch, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::MERGE_SUBTREES, lch, rch, -1); return id; } static int add_root(int ch, int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::ADD_ROOT, ch, -1, v); return id; } static int merge_paths(int hi, int lo, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::MERGE_PATHS, hi, lo, -1); return id; } }; public: static_toptree() = default; static_toptree(const std::vector<std::vector<int>> &g, int root) : _n(g.size()), _g(g), _par(_n, -1), _sub(_n), _idx(_n) { [&, dfs = [&](auto dfs, int u, int p) -> void { _par[u] = p; int max_sub = -1; _sub[u] = 1; for (int i = 0, siz = _g[u].size(); i < siz; ++i) { const int v = _g[u][i]; if (v == p) { std::swap(_g[u][i], _g[u].back()); _g[u].pop_back(); --i, --siz; } else { dfs(dfs, v, u); _sub[u] += _sub[v]; if (_sub[v] > max_sub) { // heavy path std::swap(_g[u].front(), _g[u][i]); max_sub = _sub[v]; } } } }]{ dfs(dfs, root, -1); }(); _toptree_root = _merge_paths(_heavy_path(root)); } /** * Path: with root * Subtree: without root * vertex: vertex -> Path * add_edge: Path, root, par[root] -> Subtree * merge_subtrees: Subtree, Subtree -> Subtree * add_root: Subtree, root -> Path * merge_paths: Path (hi), Path (lo) -> Path */ template < typename Subtree, typename Path, Path (*vertex)(int), Subtree (*add_edge)(Path&, int, int), Subtree (*merge_subtrees)(Subtree&, Subtree&), Path (*add_root)(Subtree&, int), Path (*merge_paths)(Path&, Path&)> auto tree_dp() const & { struct tree_dp_impl { friend static_toptree; tree_dp_impl() = delete; const Path& operator()() const { return _pdp[_toptree->_toptree_root]; } const Path& answer() const { return (*this)(); } const Path& update(int v) { for (int k = _toptree->_idx[v];; k = _toptree->_nodes[k].par_id) { _update(k); if (k == _toptree->_toptree_root) { break; } } return _pdp[_toptree->_toptree_root]; } private: const static_toptree* _toptree; std::vector<Subtree> _sdp; std::vector<Path> _pdp; tree_dp_impl(const static_toptree* toptree) : _toptree(toptree), _sdp(_toptree->_node_num()), _pdp(_toptree->_node_num()) { _init(toptree->_toptree_root); } void _update(int k) { const Node &node = _toptree->_nodes[k]; const int v = node.v; if (node.tag == NodeTag::VERTEX) { _pdp[k] = vertex(v); } else if (node.tag == NodeTag::MERGE_PATHS) { _pdp[k] = merge_paths(_pdp[node.ch_id[0]], _pdp[node.ch_id[1]]); } else if (node.tag == NodeTag::MERGE_SUBTREES) { _sdp[k] = merge_subtrees(_sdp[node.ch_id[0]], _sdp[node.ch_id[1]]); } else if (node.tag == NodeTag::ADD_EDGE) { const int p = _toptree->_par[v]; _sdp[k] = add_edge(_pdp[node.ch_id[0]], v, p); } else if (node.tag == NodeTag::ADD_ROOT) { _pdp[k] = add_root(_sdp[node.ch_id[0]], v); } else { assert(false); } } void _init(int k) { const Node& node = _toptree->_nodes[k]; const int lch = node.ch_id[0], rch = node.ch_id[1]; if (lch != -1) _init(lch); if (rch != -1) _init(rch); _update(k); } }; return tree_dp_impl{ this }; } int parent(int u) const { return _par[u]; } int subtree_size(int u) const { return _sub[u]; } private: int _n; std::vector<std::vector<int>> _g; std::vector<int> _par, _sub, _idx; std::vector<Node> _nodes; int _toptree_root; int _node_num() const { return _nodes.size(); } int _sub_size(int u) const { return _sub[u]; } int _sub_size_without_heavy_child(int u) const { return _sub[u] - (_g[u].empty() ? 0 : _sub[_g[u].front()]); } std::vector<int> _heavy_path(int u) const { std::vector<int> heavy_path{ u }; for (int cur = u; _g[cur].size();) { const int nxt = _g[cur].front(); heavy_path.push_back(nxt); cur = nxt; } return heavy_path; } // S int _add_edge(int u) { const int ch_id = _merge_paths(_heavy_path(u)); const int res = Node::add_edge(ch_id, u, _nodes); _nodes[ch_id].par_id = res; return res; } // P int _add_root(int u) { int res; if (_g[u].size() <= 1) { res = Node::vertex(u, _nodes); } else { const int ch_id = _merge_subtrees({ _g[u].begin() + 1, _g[u].end() }); res = Node::add_root(ch_id, u, _nodes); _nodes[ch_id].par_id = res; } return _idx[u] = res; } // S int _merge_subtrees(const std::vector<int> &ch) { if (ch.size() == 1) { const int v = ch.front(); return _add_edge(v); } std::vector<int> lch, rch; int diff = 0; for (int v : ch) diff += _sub_size(v); for (int v : ch) { diff -= 2 * _sub_size(v); (diff >= 0 or lch.empty() ? lch : rch).push_back(v); } const int lch_id = _merge_subtrees(std::move(lch)); const int rch_id = _merge_subtrees(std::move(rch)); const int res = Node::merge_subtrees(lch_id, rch_id, _nodes); _nodes[lch_id].par_id = res; _nodes[rch_id].par_id = res; return res; } // P int _merge_paths(const std::vector<int> &heavy_path) { if (heavy_path.size() == 1) { const int v = heavy_path.front(); return _add_root(v); } std::vector<int> hi, lo; int diff = 0; for (int v : heavy_path) diff += _sub_size_without_heavy_child(v); for (int v : heavy_path) { diff -= 2 * _sub_size_without_heavy_child(v); (diff >= 0 or hi.empty() ? hi : lo).push_back(v); } const int hi_id = _merge_paths(std::move(hi)); const int lo_id = _merge_paths(std::move(lo)); const int res = Node::merge_paths(hi_id, lo_id, _nodes); _nodes[hi_id].par_id = res; _nodes[lo_id].par_id = res; return res; } }; } // namespace suisen #endif // SUISEN_STATIC_TOP_TREE_HPP
#line 1 "library/tree/static_top_tree.hpp" #include <cassert> #include <vector> namespace suisen { struct static_toptree { private: enum class NodeTag { VERTEX, ADD_EDGE, MERGE_SUBTREES, ADD_ROOT, MERGE_PATHS, }; struct Node { NodeTag tag; int ch_id[2]{ -1, -1 }; int par_id = -1; int v; Node(NodeTag tag, int lch, int rch, int v) : tag(tag), ch_id{ lch, rch }, v(v) {} static int vertex(int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::VERTEX, -1, -1, v); return id; } static int add_edge(int ch, int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::ADD_EDGE, ch, -1, v); return id; } static int merge_subtrees(int lch, int rch, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::MERGE_SUBTREES, lch, rch, -1); return id; } static int add_root(int ch, int v, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::ADD_ROOT, ch, -1, v); return id; } static int merge_paths(int hi, int lo, std::vector<Node> &pool) { const int id = pool.size(); pool.emplace_back(NodeTag::MERGE_PATHS, hi, lo, -1); return id; } }; public: static_toptree() = default; static_toptree(const std::vector<std::vector<int>> &g, int root) : _n(g.size()), _g(g), _par(_n, -1), _sub(_n), _idx(_n) { [&, dfs = [&](auto dfs, int u, int p) -> void { _par[u] = p; int max_sub = -1; _sub[u] = 1; for (int i = 0, siz = _g[u].size(); i < siz; ++i) { const int v = _g[u][i]; if (v == p) { std::swap(_g[u][i], _g[u].back()); _g[u].pop_back(); --i, --siz; } else { dfs(dfs, v, u); _sub[u] += _sub[v]; if (_sub[v] > max_sub) { // heavy path std::swap(_g[u].front(), _g[u][i]); max_sub = _sub[v]; } } } }]{ dfs(dfs, root, -1); }(); _toptree_root = _merge_paths(_heavy_path(root)); } /** * Path: with root * Subtree: without root * vertex: vertex -> Path * add_edge: Path, root, par[root] -> Subtree * merge_subtrees: Subtree, Subtree -> Subtree * add_root: Subtree, root -> Path * merge_paths: Path (hi), Path (lo) -> Path */ template < typename Subtree, typename Path, Path (*vertex)(int), Subtree (*add_edge)(Path&, int, int), Subtree (*merge_subtrees)(Subtree&, Subtree&), Path (*add_root)(Subtree&, int), Path (*merge_paths)(Path&, Path&)> auto tree_dp() const & { struct tree_dp_impl { friend static_toptree; tree_dp_impl() = delete; const Path& operator()() const { return _pdp[_toptree->_toptree_root]; } const Path& answer() const { return (*this)(); } const Path& update(int v) { for (int k = _toptree->_idx[v];; k = _toptree->_nodes[k].par_id) { _update(k); if (k == _toptree->_toptree_root) { break; } } return _pdp[_toptree->_toptree_root]; } private: const static_toptree* _toptree; std::vector<Subtree> _sdp; std::vector<Path> _pdp; tree_dp_impl(const static_toptree* toptree) : _toptree(toptree), _sdp(_toptree->_node_num()), _pdp(_toptree->_node_num()) { _init(toptree->_toptree_root); } void _update(int k) { const Node &node = _toptree->_nodes[k]; const int v = node.v; if (node.tag == NodeTag::VERTEX) { _pdp[k] = vertex(v); } else if (node.tag == NodeTag::MERGE_PATHS) { _pdp[k] = merge_paths(_pdp[node.ch_id[0]], _pdp[node.ch_id[1]]); } else if (node.tag == NodeTag::MERGE_SUBTREES) { _sdp[k] = merge_subtrees(_sdp[node.ch_id[0]], _sdp[node.ch_id[1]]); } else if (node.tag == NodeTag::ADD_EDGE) { const int p = _toptree->_par[v]; _sdp[k] = add_edge(_pdp[node.ch_id[0]], v, p); } else if (node.tag == NodeTag::ADD_ROOT) { _pdp[k] = add_root(_sdp[node.ch_id[0]], v); } else { assert(false); } } void _init(int k) { const Node& node = _toptree->_nodes[k]; const int lch = node.ch_id[0], rch = node.ch_id[1]; if (lch != -1) _init(lch); if (rch != -1) _init(rch); _update(k); } }; return tree_dp_impl{ this }; } int parent(int u) const { return _par[u]; } int subtree_size(int u) const { return _sub[u]; } private: int _n; std::vector<std::vector<int>> _g; std::vector<int> _par, _sub, _idx; std::vector<Node> _nodes; int _toptree_root; int _node_num() const { return _nodes.size(); } int _sub_size(int u) const { return _sub[u]; } int _sub_size_without_heavy_child(int u) const { return _sub[u] - (_g[u].empty() ? 0 : _sub[_g[u].front()]); } std::vector<int> _heavy_path(int u) const { std::vector<int> heavy_path{ u }; for (int cur = u; _g[cur].size();) { const int nxt = _g[cur].front(); heavy_path.push_back(nxt); cur = nxt; } return heavy_path; } // S int _add_edge(int u) { const int ch_id = _merge_paths(_heavy_path(u)); const int res = Node::add_edge(ch_id, u, _nodes); _nodes[ch_id].par_id = res; return res; } // P int _add_root(int u) { int res; if (_g[u].size() <= 1) { res = Node::vertex(u, _nodes); } else { const int ch_id = _merge_subtrees({ _g[u].begin() + 1, _g[u].end() }); res = Node::add_root(ch_id, u, _nodes); _nodes[ch_id].par_id = res; } return _idx[u] = res; } // S int _merge_subtrees(const std::vector<int> &ch) { if (ch.size() == 1) { const int v = ch.front(); return _add_edge(v); } std::vector<int> lch, rch; int diff = 0; for (int v : ch) diff += _sub_size(v); for (int v : ch) { diff -= 2 * _sub_size(v); (diff >= 0 or lch.empty() ? lch : rch).push_back(v); } const int lch_id = _merge_subtrees(std::move(lch)); const int rch_id = _merge_subtrees(std::move(rch)); const int res = Node::merge_subtrees(lch_id, rch_id, _nodes); _nodes[lch_id].par_id = res; _nodes[rch_id].par_id = res; return res; } // P int _merge_paths(const std::vector<int> &heavy_path) { if (heavy_path.size() == 1) { const int v = heavy_path.front(); return _add_root(v); } std::vector<int> hi, lo; int diff = 0; for (int v : heavy_path) diff += _sub_size_without_heavy_child(v); for (int v : heavy_path) { diff -= 2 * _sub_size_without_heavy_child(v); (diff >= 0 or hi.empty() ? hi : lo).push_back(v); } const int hi_id = _merge_paths(std::move(hi)); const int lo_id = _merge_paths(std::move(lo)); const int res = Node::merge_paths(hi_id, lo_id, _nodes); _nodes[hi_id].par_id = res; _nodes[lo_id].par_id = res; return res; } }; } // namespace suisen