diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 7562f33..a3cf204 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -1,4 +1,5 @@ { +"test/aoj-1595.test.cpp": "2024-08-13 01:24:17 +0900", "test/aoj-3314.test.cpp": "2023-10-12 08:50:40 +0900", "test/aoj-alds1-3-c.test.py": "2023-09-05 02:43:56 +0900", "test/aoj-cgl-2-b.test.cpp": "2023-09-07 23:01:33 +0900", diff --git a/cpp/rerooting-dp.hpp b/cpp/rerooting-dp.hpp new file mode 100644 index 0000000..d9200ee --- /dev/null +++ b/cpp/rerooting-dp.hpp @@ -0,0 +1,99 @@ +#pragma once + +/** + * @file rerooting-dp.hpp + * @brief 全方位木DP + */ +#include +#include +#include +#include "tree.hpp" + +/** + * @brief 全方位木DP + * dp[u] = addnode(merge(addedge(dp[v1], uv1.cost, uv1.id), merge(addedge(dp[v2], uv2.cost, uv2.id), ...)), u) v_iはuの子 + * + * @tparam E 可換モノイド + * @tparam V DPの型 + * @param tree + * @param e 可換モノイドの単位元 + * @param merge (E,E)->E 可換 + * @param addedge (V,Cost,int)->E + * @param addnode (E,int)->V + * @return std::vector + */ +template +std::vector rerooting_dp(const Tree& tree, E e, Merge merge, AddEdge addedge, AddNode addnode) { + static_assert(std::is_invocable_r_v); + static_assert(std::is_invocable_r_v); + static_assert(std::is_invocable_r_v); + RootedTree rooted(tree, 0); + std::vector subdp(rooted.n); + for (int u : rooted.postorder) { + E tmp = e; + for (auto edge : rooted.child[u]) { + tmp = merge(tmp, addedge(subdp[edge.dst], edge.cost, edge.id)); + } + subdp[u] = addnode(tmp, u); + } + std::vector dp(rooted.n); + std::vector pe(rooted.n, e); + for (int u : rooted.preorder) { + const auto& ch = rooted.child[u]; + std::vector ri(ch.size() + 1, e); + for (std::size_t i = ch.size(); i > 0; i--) { + ri[i - 1] = merge(ri[i], addedge(subdp[ch[i - 1].dst], ch[i - 1].cost, ch[i - 1].id)); + } + dp[u] = addnode(merge(pe[u], ri[0]), u); + E le = pe[u]; + for (std::size_t i = 0; i < ch.size(); i++) { + pe[ch[i].dst] = addedge(addnode(merge(le, ri[i + 1]), u), ch[i].cost, ch[i].id); + le = merge(le, addedge(subdp[ch[i].dst], ch[i].cost, ch[i].id)); + } + } + return dp; +} + +/** + * @brief 最も遠い頂点までの距離 + */ +template +inline std::vector farthest_node_dist(const Tree& tree) { + return rerooting_dp( + tree, + Cost{}, + [](Cost a, Cost b) { return std::max(a, b); }, + [](Cost a, Cost c, int) { return a + c; }, + [](Cost a, int) { return a; }); +} + +/** + * @brief 他の全ての頂点との距離の合計 + */ +template +inline std::vector distance_sums(const Tree& tree) { + using P = typename std::pair; + auto tmp = rerooting_dp( + tree, + P{{}, 0}, + [](P a, P b) { return P{a.first + b.first, a.second + b.second}; }, + [](P a, Cost c, int) { return P{a.first + a.second * c, a.second}; }, + [](P a, int) { return P{a.first, a.second + 1}; }); + std::vector res; + res.reserve(tree.n); + for (const P& s : tmp) res.push_back(s.first); + return res; +} + +/** + * @brief その頂点を含む連結な部分グラフの個数 + */ +template +inline std::vector connected_subgraph_count(const Tree& tree) { + return rerooting_dp( + tree, + V(1), + [](V a, V b) { return a * b; }, + [](V a, Cost c, int) { return a + 1; }, + [](V a, int) { return a; }); +} diff --git a/test/aoj-1595.test.cpp b/test/aoj-1595.test.cpp new file mode 100644 index 0000000..c59988d --- /dev/null +++ b/test/aoj-1595.test.cpp @@ -0,0 +1,16 @@ +#define PROBLEM "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=1595" + +#include + +#include "../cpp/rerooting-dp.hpp" + +int main() { + int N; + std::cin >> N; + Tree tree(N); + tree.read(); + auto ans = farthest_node_dist(tree); + for (int i = 0; i < N; i++) { + std::cout << 2 * N - 2 - ans[i] << std::endl; + } +}