diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 026eb378..9c0e00c1 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -71,9 +71,9 @@ "tests/library_checker_aizu_tests/graphs/strongly_connected_components_aizu.test.cpp": "2026-01-17 13:05:42 -0700", "tests/library_checker_aizu_tests/graphs/strongly_connected_components_lib_checker.test.cpp": "2026-01-17 13:05:42 -0700", "tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2026-02-27 11:16:07 -0700", -"tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2026-03-16 14:02:06 -0600", +"tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2026-03-16 14:23:41 -0600", "tests/library_checker_aizu_tests/handmade_tests/dsu.test.cpp": "2026-01-22 10:08:22 -0700", -"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2026-03-16 13:39:47 -0600", +"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2026-03-16 14:23:41 -0600", "tests/library_checker_aizu_tests/handmade_tests/fib_matrix_expo.test.cpp": "2026-01-28 21:48:16 -0700", "tests/library_checker_aizu_tests/handmade_tests/functional_graph.test.cpp": "2025-08-06 16:18:37 -0600", "tests/library_checker_aizu_tests/handmade_tests/hilbert_mos.test.cpp": "2026-01-18 02:20:40 +0000", @@ -128,11 +128,11 @@ "tests/library_checker_aizu_tests/strings/suffix_array_short.test.cpp": "2026-01-28 01:00:19 -0700", "tests/library_checker_aizu_tests/strings/trie.test.cpp": "2026-01-17 12:38:18 -0700", "tests/library_checker_aizu_tests/strings/wildcard_pattern_matching.test.cpp": "2025-08-05 19:19:23 -0600", -"tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2026-03-16 13:39:47 -0600", -"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp": "2026-03-16 13:39:47 -0600", -"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp": "2026-03-16 13:39:47 -0600", -"tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp": "2026-03-16 13:39:47 -0600", -"tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp": "2026-03-16 13:39:47 -0600", +"tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp": "2026-03-16 14:13:24 -0600", +"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp": "2026-03-16 14:23:41 -0600", +"tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp": "2026-03-16 14:23:41 -0600", +"tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp": "2026-03-16 14:23:41 -0600", +"tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp": "2026-03-16 14:23:41 -0600", "tests/library_checker_aizu_tests/trees/hld_aizu1.test.cpp": "2026-01-18 11:15:41 +0000", "tests/library_checker_aizu_tests/trees/hld_aizu2.test.cpp": "2026-01-23 04:31:29 +0000", "tests/library_checker_aizu_tests/trees/hld_lib_checker_path.test.cpp": "2026-01-18 11:15:41 +0000", diff --git a/library/trees/edge_cd.hpp b/library/trees/edge_cd.hpp index f90e38ae..372309c0 100644 --- a/library/trees/edge_cd.hpp +++ b/library/trees/edge_cd.hpp @@ -5,7 +5,7 @@ //! https://youtu.be/wDwaMo5xa-k //! @code //! vector> adj(n); -//! edge_cd(adj, [&](const auto& adj, int cent, int m) { +//! edge_cd(adj, [&](int cent, int m) { //! // subtrees of [0, m) of adj[cent]: 1st edge-set //! // subtrees of [m, sz(adj[cent])): 2nd edge-set //! }); @@ -13,39 +13,36 @@ //! handle single-edge-paths separately //! @time O(n logφ n) //! @space O(n) -template struct edge_cd { - vector adj; - F f; - vi siz; - edge_cd(const vector& adj, F f): - adj(adj), f(f), siz(sz(adj)) { - dfs(0, sz(adj) - 1); - } - int find_cent(int u, int p, int m) { +template +void edge_cd(vector& adj, const auto& f) { + vi siz(sz(adj)); + auto find_cent = [&](auto&& self, int u, int p, + int m) -> int { siz[u] = 1; for (int v : adj[u]) if (v != p) { - int cent = find_cent(v, u, m); + int cent = self(self, v, u, m); if (cent != -1) return cent; siz[u] += siz[v]; } return 2 * siz[u] > m ? p >= 0 && (siz[p] = m + 1 - siz[u]), u : -1; - } - void dfs(int u, int m) { + }; + auto dfs = [&](auto&& self, int u, int m) -> void { if (m < 2) return; - u = find_cent(u, -1, m); + u = find_cent(find_cent, u, -1, m); int sum = 0; auto it = partition(all(adj[u]), [&](int v) { ll x = sum + siz[v]; return x * x < m * (m - x) ? sum += siz[v], 1 : 0; }); - f(adj, u, it - begin(adj[u])); + f(u, it - begin(adj[u])); G oth(it, end(adj[u])); adj[u].erase(it, end(adj[u])); - dfs(u, sum); + self(self, u, sum); swap(adj[u], oth); - dfs(u, m - sum); - } + self(self, u, m - sum); + }; + dfs(dfs, 0, sz(adj) - 1); }; diff --git a/tests/library_checker_aizu_tests/edge_cd_asserts.hpp b/tests/library_checker_aizu_tests/edge_cd_asserts.hpp index 808806a3..87984201 100644 --- a/tests/library_checker_aizu_tests/edge_cd_asserts.hpp +++ b/tests/library_checker_aizu_tests/edge_cd_asserts.hpp @@ -1,6 +1,5 @@ #pragma once -void edge_cd_asserts(const vector& adj, int cent, - int split) { +auto edge_cd_asserts = [&](int cent, int split) -> void { assert(0 < split && split < sz(adj[cent])); auto dfs = [&](auto&& self, int u, int p) -> int { int siz = 1; @@ -47,4 +46,4 @@ void edge_cd_asserts(const vector& adj, int cent, assert(!is_balanced(a, cnts[0] + b)); assert(!is_balanced(b, cnts[0] + a)); } -} +}; diff --git a/tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp index b8bd199d..b6acb020 100644 --- a/tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp +++ b/tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp @@ -91,24 +91,23 @@ vector> naive(const vector& adj) { //! @time O(n * logφ(n) * log2(n)) //! @space this function allocates/returns various vectors //! which are each O(n) -vector count_paths_per_length(const vector& adj) { +vector count_paths_per_length(vector adj) { vector num_paths(sz(adj)); if (sz(adj) >= 2) num_paths[1] = sz(adj) - 1; - edge_cd(adj, - [&](const vector& cd_adj, int cent, int split) { - vector> cnt(2, vector(1)); - auto dfs = [&](auto&& self, int u, int p, int d, - int side) -> void { - if (sz(cnt[side]) == d) cnt[side].push_back(0.0); - cnt[side][d]++; - for (int c : cd_adj[u]) - if (c != p) self(self, c, u, 1 + d, side); - }; - rep(i, 0, sz(cd_adj[cent])) - dfs(dfs, cd_adj[cent][i], cent, 1, i < split); - vector prod = conv(cnt[0], cnt[1]); - rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); - }); + edge_cd(adj, [&](int cent, int split) { + vector> cnt(2, vector(1)); + auto dfs = [&](auto&& self, int u, int p, int d, + int side) -> void { + if (sz(cnt[side]) == d) cnt[side].push_back(0.0); + cnt[side][d]++; + for (int c : adj[u]) + if (c != p) self(self, c, u, 1 + d, side); + }; + rep(i, 0, sz(adj[cent])) + dfs(dfs, adj[cent][i], cent, 1, i < split); + vector prod = conv(cnt[0], cnt[1]); + rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); + }); return num_paths; } int main() { diff --git a/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp index e8c20167..3c664001 100644 --- a/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp +++ b/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp @@ -1,23 +1,16 @@ #define PROBLEM \ "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" #include "../template.hpp" -#include "../edge_cd_asserts.hpp" #include "../../../kactl/stress-tests/utilities/genTree.h" #include "../../../library/trees/edge_cd.hpp" int main() { { vector> adj; - edge_cd(adj, - [&](const vector>&, int, int) -> void { - assert(false); - }); + edge_cd(adj, [&](int, int) -> void { assert(false); }); } { vector> adj(1); - edge_cd(adj, - [&](const vector>&, int, int) -> void { - assert(false); - }); + edge_cd(adj, [&](int, int) -> void { assert(false); }); } for (int n = 2; n <= 7; n++) { int num_codes = 1; @@ -42,6 +35,7 @@ int main() { adj[u].push_back(v); adj[v].push_back(u); } +#include "../edge_cd_asserts.hpp" edge_cd(adj, edge_cd_asserts); } } diff --git a/tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp b/tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp index 8c2afaad..95871501 100644 --- a/tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp +++ b/tests/library_checker_aizu_tests/trees/count_paths_per_length.test.cpp @@ -9,24 +9,23 @@ //! @time O(n * logφ(n) * log2(n)) //! @space this function allocates/returns various vectors //! which are each O(n) -vector count_paths_per_length(const vector& adj) { +vector count_paths_per_length(vector& adj) { vector num_paths(sz(adj)); if (sz(adj) >= 2) num_paths[1] = sz(adj) - 1; - edge_cd(adj, - [&](const vector& cd_adj, int cent, int split) { - vector> cnt(2, vector(1)); - auto dfs = [&](auto&& self, int u, int p, int d, - int side) -> void { - if (sz(cnt[side]) == d) cnt[side].push_back(0.0); - cnt[side][d]++; - for (int c : cd_adj[u]) - if (c != p) self(self, c, u, 1 + d, side); - }; - rep(i, 0, sz(cd_adj[cent])) - dfs(dfs, cd_adj[cent][i], cent, 1, i < split); - vector prod = conv(cnt[0], cnt[1]); - rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); - }); + edge_cd(adj, [&](int cent, int split) { + vector> cnt(2, vector(1)); + auto dfs = [&](auto&& self, int u, int p, int d, + int side) -> void { + if (sz(cnt[side]) == d) cnt[side].push_back(0.0); + cnt[side][d]++; + for (int c : adj[u]) + if (c != p) self(self, c, u, 1 + d, side); + }; + rep(i, 0, sz(adj[cent])) + dfs(dfs, adj[cent][i], cent, 1, i < split); + vector prod = conv(cnt[0], cnt[1]); + rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); + }); return num_paths; } int main() { diff --git a/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp b/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp index 9824d42a..106ad1a6 100644 --- a/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp +++ b/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp @@ -1,7 +1,6 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/vertex_add_range_contour_sum_on_tree" #include "../template.hpp" -#include "../edge_cd_asserts.hpp" #include "../../../library/data_structures_[l,r)/bit.hpp" #include "../../../library/trees/edge_cd.hpp" struct sum_adj { @@ -47,25 +46,23 @@ struct contour_range_query { //! @param a a[u] = initial number for node u //! @time O(n logφ n) //! @space O(n logφ n) for `info` and `bits` - contour_range_query(const vector& adj, - const vector& a): + contour_range_query(vector adj, const vector& a): n(sz(a)), sum_a(adj, a), info(n) { - edge_cd(adj, - [&](const vector& cd_adj, int cent, int split) { - vector> sum_num(2, vector(1)); - auto dfs = [&](auto&& self, int u, int p, int d, - int side) -> void { - info[u].push_back({int(sz(bits)), d, side}); - if (sz(sum_num[side]) == d) - sum_num[side].push_back(0); - sum_num[side][d] += a[u]; - for (int c : cd_adj[u]) - if (c != p) self(self, c, u, 1 + d, side); - }; - rep(i, 0, sz(cd_adj[cent])) - dfs(dfs, cd_adj[cent][i], cent, 1, i < split); - bits.push_back({BIT(sum_num[0]), BIT(sum_num[1])}); - }); + edge_cd(adj, [&](int cent, int split) { + vector> sum_num(2, vector(1)); + auto dfs = [&](auto&& self, int u, int p, int d, + int side) -> void { + info[u].push_back({int(sz(bits)), d, side}); + if (sz(sum_num[side]) == d) + sum_num[side].push_back(0); + sum_num[side][d] += a[u]; + for (int c : adj[u]) + if (c != p) self(self, c, u, 1 + d, side); + }; + rep(i, 0, sz(adj[cent])) + dfs(dfs, adj[cent][i], cent, 1, i < split); + bits.push_back({BIT(sum_num[0]), BIT(sum_num[1])}); + }); } //! @param u node //! @param delta number to add to node u's number @@ -108,8 +105,11 @@ int main() { adj[u].push_back(v); adj[v].push_back(u); } - { edge_cd(adj, edge_cd_asserts); } contour_range_query cq(adj, a); + { +#include "../edge_cd_asserts.hpp" + edge_cd(adj, edge_cd_asserts); + } while (q--) { int type; cin >> type; diff --git a/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp b/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp index 0923218a..93775fe9 100644 --- a/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp +++ b/tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp @@ -1,7 +1,6 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/vertex_get_range_contour_add_on_tree" #include "../template.hpp" -#include "../edge_cd_asserts.hpp" #include "../../../library/data_structures_[l,r)/bit_uncommon/rupq.hpp" #include "../../../library/trees/edge_cd.hpp" struct sum_adj { @@ -49,24 +48,23 @@ struct contour_range_update { //! @param a a[u] = initial number for node u //! @time O(n logφ n) //! @space O(n logφ n) for `info` and `bits` - contour_range_update(const vector& adj, + contour_range_update(vector adj, const vector& a): n(sz(a)), a(a), sum_a(adj, vector(n)), info(n) { - edge_cd(adj, - [&](const vector& cd_adj, int cent, int split) { - array mx_d = {0, 0}; - auto dfs = [&](auto&& self, int u, int p, int d, - int side) -> void { - mx_d[side] = max(mx_d[side], d); - info[u].push_back({int(sz(bits)), d, side}); - for (int v : cd_adj[u]) - if (v != p) self(self, v, u, 1 + d, side); - }; - rep(i, 0, sz(cd_adj[cent])) - dfs(dfs, cd_adj[cent][i], cent, 1, i < split); - bits.push_back( - {bit_rupq(mx_d[0] + 1), bit_rupq(mx_d[1] + 1)}); - }); + edge_cd(adj, [&](int cent, int split) { + array mx_d = {0, 0}; + auto dfs = [&](auto&& self, int u, int p, int d, + int side) -> void { + mx_d[side] = max(mx_d[side], d); + info[u].push_back({int(sz(bits)), d, side}); + for (int v : adj[u]) + if (v != p) self(self, v, u, 1 + d, side); + }; + rep(i, 0, sz(adj[cent])) + dfs(dfs, adj[cent][i], cent, 1, i < split); + bits.push_back( + {bit_rupq(mx_d[0] + 1), bit_rupq(mx_d[1] + 1)}); + }); } //! @param u,l,r,delta add delta to all nodes v such //! that l <= dist(u, v) < r @@ -106,8 +104,11 @@ int main() { adj[u].push_back(v); adj[v].push_back(u); } - { edge_cd(adj, edge_cd_asserts); } contour_range_update cu(adj, a); + { +#include "../edge_cd_asserts.hpp" + edge_cd(adj, edge_cd_asserts); + } while (q--) { int type; cin >> type; diff --git a/tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp b/tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp index dcdc96b4..6c34c424 100644 --- a/tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp +++ b/tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp @@ -1,7 +1,6 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/frequency_table_of_tree_distance" #include "../template.hpp" -#include "../edge_cd_asserts.hpp" #include "../../../kactl/content/numerical/FastFourierTransform.h" #include "../../../library/trees/edge_cd.hpp" //! @param adj unrooted, connected tree @@ -10,24 +9,23 @@ //! @time O(n * logφ(n) * log2(n)) //! @space this function allocates/returns various vectors //! which are each O(n) -vector count_paths_per_length(const vector& adj) { +vector count_paths_per_length(vector adj) { vector num_paths(sz(adj)); if (sz(adj) >= 2) num_paths[1] = sz(adj) - 1; - edge_cd(adj, - [&](const vector& cd_adj, int cent, int split) { - vector> cnt(2, vector(1)); - auto dfs = [&](auto&& self, int u, int p, int d, - int side) -> void { - if (sz(cnt[side]) == d) cnt[side].push_back(0.0); - cnt[side][d]++; - for (int c : cd_adj[u]) - if (c != p) self(self, c, u, 1 + d, side); - }; - rep(i, 0, sz(cd_adj[cent])) - dfs(dfs, cd_adj[cent][i], cent, 1, i < split); - vector prod = conv(cnt[0], cnt[1]); - rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); - }); + edge_cd(adj, [&](int cent, int split) { + vector> cnt(2, vector(1)); + auto dfs = [&](auto&& self, int u, int p, int d, + int side) -> void { + if (sz(cnt[side]) == d) cnt[side].push_back(0.0); + cnt[side][d]++; + for (int c : adj[u]) + if (c != p) self(self, c, u, 1 + d, side); + }; + rep(i, 0, sz(adj[cent])) + dfs(dfs, adj[cent][i], cent, 1, i < split); + vector prod = conv(cnt[0], cnt[1]); + rep(i, 0, sz(prod)) num_paths[i] += llround(prod[i]); + }); return num_paths; } int main() { @@ -41,8 +39,11 @@ int main() { adj[u].push_back(v); adj[v].push_back(u); } - { edge_cd(adj, edge_cd_asserts); } vector cnt_len = count_paths_per_length(adj); + { +#include "../edge_cd_asserts.hpp" + edge_cd(adj, edge_cd_asserts); + } for (int i = 1; i < n; i++) cout << cnt_len[i] << " "; cout << '\n'; return 0; diff --git a/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp b/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp index b7548c9d..223a8e19 100644 --- a/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp +++ b/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp @@ -1,7 +1,6 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/tree_path_composite_sum" #include "../template.hpp" -#include "../edge_cd_asserts.hpp" #include "../../../library/trees/edge_cd.hpp" const int mod = 998244353; int main() { @@ -45,57 +44,58 @@ int main() { assert(u_low ^ v_low); return u_low ? par[u].second : par[v].second; }; - { edge_cd(base_adj, edge_cd_asserts); } - edge_cd(adj, - [&](const vector& cd_adj, int cent, - int split) -> void { - array>, 2> all_backwards; - array sum_forward = {0, 0}; - array cnt_nodes = {0, 0}; - auto dfs = [&](auto&& self, int u, int p, - array forwards, - array backwards, - int side) -> void { - all_backwards[side].push_back( - {u, backwards[0], backwards[1]}); - sum_forward[side] = - (sum_forward[side] + 1LL * forwards[0] * a[u] + - forwards[1]) % - mod; - cnt_nodes[side]++; - for (int v : cd_adj[u]) { - if (v == p) continue; - int e_id = edge_id(u, v); - // f(x) = ax+b - // g(x) = cx+d - // f(g(x)) = a(cx+d)+b = acx+ad+b - array curr_forw = { - int(1LL * forwards[0] * b[e_id] % mod), - int( - (1LL * forwards[0] * c[e_id] + forwards[1]) % - mod)}; - array curr_backw = { - int(1LL * backwards[0] * b[e_id] % mod), - int((1LL * backwards[1] * b[e_id] + c[e_id]) % - mod)}; - self(self, v, u, curr_forw, curr_backw, side); - } - }; - for (int i = 0; i < sz(cd_adj[cent]); i++) { - int e_id = edge_id(cent, cd_adj[cent][i]); - dfs(dfs, cd_adj[cent][i], cent, {b[e_id], c[e_id]}, - {b[e_id], c[e_id]}, i < split); + edge_cd(adj, [&](int cent, int split) -> void { + array>, 2> all_backwards; + array sum_forward = {0, 0}; + array cnt_nodes = {0, 0}; + auto dfs = [&](auto&& self, int u, int p, + array forwards, + array backwards, + int side) -> void { + all_backwards[side].push_back( + {u, backwards[0], backwards[1]}); + sum_forward[side] = + (sum_forward[side] + 1LL * forwards[0] * a[u] + + forwards[1]) % + mod; + cnt_nodes[side]++; + for (int v : adj[u]) { + if (v == p) continue; + int e_id = edge_id(u, v); + // f(x) = ax+b + // g(x) = cx+d + // f(g(x)) = a(cx+d)+b = acx+ad+b + array curr_forw = { + int(1LL * forwards[0] * b[e_id] % mod), + int((1LL * forwards[0] * c[e_id] + forwards[1]) % + mod)}; + array curr_backw = { + int(1LL * backwards[0] * b[e_id] % mod), + int((1LL * backwards[1] * b[e_id] + c[e_id]) % + mod)}; + self(self, v, u, curr_forw, curr_backw, side); } - for (int side = 0; side < 2; side++) { - for ( - auto [u, curr_b, curr_c] : all_backwards[side]) { - res[u] = - (res[u] + 1LL * curr_b * sum_forward[!side] + - 1LL * curr_c * cnt_nodes[!side]) % - mod; - } + }; + for (int i = 0; i < sz(adj[cent]); i++) { + int e_id = edge_id(cent, adj[cent][i]); + dfs(dfs, adj[cent][i], cent, {b[e_id], c[e_id]}, + {b[e_id], c[e_id]}, i < split); + } + for (int side = 0; side < 2; side++) { + for ( + auto [u, curr_b, curr_c] : all_backwards[side]) { + res[u] = + (res[u] + 1LL * curr_b * sum_forward[!side] + + 1LL * curr_c * cnt_nodes[!side]) % + mod; } - }); + } + }); + swap(base_adj, adj); + { +#include "../edge_cd_asserts.hpp" + edge_cd(adj, edge_cd_asserts); + } for (int i = 0; i < n; i++) cout << res[i] << ' '; cout << '\n'; return 0;