Skip to content

Commit 8231ddd

Browse files
lrvideckisweb-flow
andauthored
Centroid modern style (#196)
* update centroid * [auto-verifier] verify commit 952423d --------- Co-authored-by: GitHub <noreply@github.com>
1 parent ff5d690 commit 8231ddd

File tree

4 files changed

+67
-77
lines changed

4 files changed

+67
-77
lines changed

.verify-helper/timestamps.remote.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
"tests/library_checker_aizu_tests/graphs/strongly_connected_components_aizu.test.cpp": "2026-01-17 13:05:42 -0700",
7272
"tests/library_checker_aizu_tests/graphs/strongly_connected_components_lib_checker.test.cpp": "2026-01-17 13:05:42 -0700",
7373
"tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2026-02-27 11:16:07 -0700",
74-
"tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2026-03-16 13:39:47 -0600",
74+
"tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2026-03-16 13:52:41 -0600",
7575
"tests/library_checker_aizu_tests/handmade_tests/dsu.test.cpp": "2026-01-22 10:08:22 -0700",
7676
"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2026-03-16 13:39:47 -0600",
7777
"tests/library_checker_aizu_tests/handmade_tests/fib_matrix_expo.test.cpp": "2026-01-28 21:48:16 -0700",

library/trees/centroid_decomp.hpp

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,28 @@
66
//! @endcode
77
//! @time O(n log n)
88
//! @space O(n)
9-
template<class F, class G> struct centroid {
10-
G adj;
11-
F f;
12-
vi siz;
13-
centroid(const G& adj, F f):
14-
adj(adj), f(f), siz(sz(adj), -1) {
15-
dfs(0, -1);
16-
}
17-
void calc_sz(int u, int p) {
9+
void centroid(auto& adj, const auto& f) {
10+
vi siz(sz(adj));
11+
auto calc_sz = [&](auto&& self, int u, int p) -> void {
1812
siz[u] = 1;
1913
for (int v : adj[u])
20-
if (v != p) calc_sz(v, u), siz[u] += siz[v];
21-
}
22-
void dfs(int u, int p) {
23-
calc_sz(u, -1);
14+
if (v != p) self(self, v, u), siz[u] += siz[v];
15+
};
16+
auto dfs = [&](auto&& self, int u, int p) -> void {
17+
calc_sz(calc_sz, u, -1);
2418
for (int w = -1, sz_root = siz[u];;) {
2519
auto big_ch = ranges::find_if(adj[u], [&](int v) {
2620
return v != w && 2 * siz[v] > sz_root;
2721
});
2822
if (big_ch == end(adj[u])) break;
2923
w = u, u = *big_ch;
3024
}
31-
f(adj, u, p);
25+
f(u, p);
3226
for (int v : adj[u]) {
3327
iter_swap(ranges::find(adj[v], u), rbegin(adj[v]));
3428
adj[v].pop_back();
35-
dfs(v, u);
29+
self(self, v, u);
3630
}
37-
}
38-
};
31+
};
32+
dfs(dfs, 0, -1);
33+
}
Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1 @@
11
#pragma once
2-
#include "../../library/trees/centroid_decomp.hpp"
3-
void cd_asserts(const vector<vector<int>>& adj) {
4-
vector<int> decomp_size(sz(adj), -1);
5-
vector<int> naive_par_decomp(sz(adj), -1);
6-
centroid(adj,
7-
[&](const vector<vector<int>>& cd_adj, int cent,
8-
int par_cent) -> void {
9-
assert(naive_par_decomp[cent] == par_cent);
10-
assert(decomp_size[cent] == -1);
11-
auto dfs = [&](auto&& self, int u, int p) -> int {
12-
naive_par_decomp[u] = cent;
13-
int sub_size = 1;
14-
for (int v : cd_adj[u])
15-
if (v != p) sub_size += self(self, v, u);
16-
return sub_size;
17-
};
18-
decomp_size[cent] = dfs(dfs, cent, -1);
19-
if (par_cent != -1)
20-
assert(1 <= decomp_size[cent] &&
21-
2 * decomp_size[cent] <= decomp_size[par_cent]);
22-
for (int u : cd_adj[cent]) {
23-
int sz_subtree = dfs(dfs, u, cent);
24-
assert(1 <= sz_subtree &&
25-
2 * sz_subtree <= decomp_size[cent]);
26-
}
27-
});
28-
rep(i, 0, sz(adj)) assert(decomp_size[i] >= 1);
29-
}

tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp

Lines changed: 54 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,34 @@
33
#include "../template.hpp"
44
#include "../../../library/contest/random.hpp"
55
#include "../../../library/trees/lca_rmq.hpp"
6-
#include "../cd_asserts.hpp"
76
#include "../../../kactl/content/numerical/FastFourierTransform.h"
87
#include "../../../library/trees/edge_cd.hpp"
8+
#include "../../../library/trees/centroid_decomp.hpp"
9+
void cd_asserts(vector<vector<int>> adj) {
10+
vector<int> decomp_size(sz(adj), -1);
11+
vector<int> naive_par_decomp(sz(adj), -1);
12+
centroid(adj, [&](int cent, int par_cent) -> void {
13+
assert(naive_par_decomp[cent] == par_cent);
14+
assert(decomp_size[cent] == -1);
15+
auto dfs = [&](auto&& self, int u, int p) -> int {
16+
naive_par_decomp[u] = cent;
17+
int sub_size = 1;
18+
for (int v : adj[u])
19+
if (v != p) sub_size += self(self, v, u);
20+
return sub_size;
21+
};
22+
decomp_size[cent] = dfs(dfs, cent, -1);
23+
if (par_cent != -1)
24+
assert(1 <= decomp_size[cent] &&
25+
2 * decomp_size[cent] <= decomp_size[par_cent]);
26+
for (int u : adj[cent]) {
27+
int sz_subtree = dfs(dfs, u, cent);
28+
assert(1 <= sz_subtree &&
29+
2 * sz_subtree <= decomp_size[cent]);
30+
}
31+
});
32+
rep(i, 0, sz(adj)) assert(decomp_size[i] >= 1);
33+
}
934
//! @param adj unrooted, connected forest
1035
//! @param k number of edges
1136
//! @returns array `num_paths` where `num_paths[i]` =
@@ -14,37 +39,35 @@
1439
//! @time O(n log n)
1540
//! @space this function allocates/returns various vectors
1641
//! which are all O(n)
17-
vector<ll> count_paths_per_node(const vector<vi>& adj,
18-
int k) {
42+
vector<ll> count_paths_per_node(vector<vi> adj, int k) {
1943
vector<ll> num_paths(sz(adj));
20-
centroid(adj,
21-
[&](const vector<vi>& cd_adj, int cent, int) {
22-
vector pre_d{1}, cur_d{0};
23-
auto dfs = [&](auto&& self, int u, int p,
24-
int d) -> ll {
25-
if (d > k) return 0LL;
26-
if (sz(cur_d) <= d) cur_d.push_back(0);
27-
cur_d[d]++;
28-
ll cnt = 0;
29-
if (k - d < sz(pre_d)) cnt += pre_d[k - d];
30-
for (int c : cd_adj[u])
31-
if (c != p) cnt += self(self, c, u, d + 1);
32-
num_paths[u] += cnt;
33-
return cnt;
34-
};
35-
auto dfs_child = [&](int child) -> ll {
36-
ll cnt = dfs(dfs, child, cent, 1);
37-
pre_d.resize(sz(cur_d));
38-
for (int i = 1; i < sz(cur_d) && cur_d[i]; i++)
39-
pre_d[i] += cur_d[i], cur_d[i] = 0;
40-
return cnt;
41-
};
42-
for (int child : cd_adj[cent])
43-
num_paths[cent] += dfs_child(child);
44-
pre_d = cur_d = {0};
45-
for (int child : cd_adj[cent] | views::reverse)
46-
dfs_child(child);
47-
});
44+
centroid(adj, [&](int cent, int) {
45+
vector pre_d{1}, cur_d{0};
46+
auto dfs = [&](auto&& self, int u, int p,
47+
int d) -> ll {
48+
if (d > k) return 0LL;
49+
if (sz(cur_d) <= d) cur_d.push_back(0);
50+
cur_d[d]++;
51+
ll cnt = 0;
52+
if (k - d < sz(pre_d)) cnt += pre_d[k - d];
53+
for (int c : adj[u])
54+
if (c != p) cnt += self(self, c, u, d + 1);
55+
num_paths[u] += cnt;
56+
return cnt;
57+
};
58+
auto dfs_child = [&](int child) -> ll {
59+
ll cnt = dfs(dfs, child, cent, 1);
60+
pre_d.resize(sz(cur_d));
61+
for (int i = 1; i < sz(cur_d) && cur_d[i]; i++)
62+
pre_d[i] += cur_d[i], cur_d[i] = 0;
63+
return cnt;
64+
};
65+
for (int child : adj[cent])
66+
num_paths[cent] += dfs_child(child);
67+
pre_d = cur_d = {0};
68+
for (int child : adj[cent] | views::reverse)
69+
dfs_child(child);
70+
});
4871
return num_paths;
4972
}
5073
vector<vector<ll>> naive(const vector<vi>& adj) {

0 commit comments

Comments
 (0)