@@ -60,6 +60,34 @@ vector<vector<ll>> naive(const vector<vi>& adj) {
6060 }
6161 return cnts_naive;
6262}
63+ #include " ../../../kactl/content/numerical/FastFourierTransform.h"
64+ #include " ../../../library/trees/edge_cd.hpp"
65+ // ! @param adj unrooted, connected tree
66+ // ! @returns array `num_paths` where `num_paths[i]` = # of
67+ // ! paths in tree with `i` edges. `num_paths[1]` = # edges
68+ // ! @time O(n * logφ(n) * log2(n))
69+ // ! @space this function allocates/returns various vectors
70+ // ! which are each O(n)
71+ vector<ll> count_paths_per_length (const vector<vi>& adj) {
72+ vector<ll> num_paths (sz (adj));
73+ if (sz (adj) >= 2 ) num_paths[1 ] = sz (adj) - 1 ;
74+ edge_cd (adj,
75+ [&](const vector<vi>& cd_adj, int cent, int split) {
76+ vector<vector<double >> cnt (2 , vector<double >(1 ));
77+ auto dfs = [&](auto && self, int u, int p, int d,
78+ int side) -> void {
79+ if (sz (cnt[side]) == d) cnt[side].push_back (0.0 );
80+ cnt[side][d]++;
81+ for (int c : cd_adj[u])
82+ if (c != p) self (self, c, u, 1 + d, side);
83+ };
84+ rep (i, 0 , sz (cd_adj[cent]))
85+ dfs (dfs, cd_adj[cent][i], cent, 1 , i < split);
86+ vector<double > prod = conv (cnt[0 ], cnt[1 ]);
87+ rep (i, 0 , sz (prod)) num_paths[i] += llround (prod[i]);
88+ });
89+ return num_paths;
90+ }
6391int main () {
6492 cin.tie (0 )->sync_with_stdio (0 );
6593 for (int n = 1 ; n <= 100 ; n++) {
0 commit comments