This documentation is automatically generated by online-judge-tools/verification-helper
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/frequency_table_of_tree_distance
#include "../../template/template.hpp"
#include "../../graph/tree/centroid-decomposition.hpp"
#include "../../math/fft/fast-fourier-transform.hpp"
int main() {
int N;
cin >> N;
CentroidDecomposition< int > g(N);
g.read(N - 1, 0);
int root = g.build();
vector< int > used(N);
vector< int64 > dist(N);
MFP([&](auto rec, int centroid) -> void {
used[centroid] = true;
vector< int > cnt{1};
for(auto &ch : g.g[centroid]) {
if(used[ch]) continue;
vector< int > num;
queue< tuple< int, int, int > > que;
que.emplace(ch, centroid, 1);
while(!que.empty()) {
int idx, par, dep;
tie(idx, par, dep) = que.front();
que.pop();
if(cnt.size() <= dep) cnt.resize(dep + 1, 0);
if(num.size() <= dep) num.resize(dep + 1, 0);
cnt[dep]++;
num[dep]++;
for(auto &to : g.g[idx]) {
if(to == par || used[to]) continue;
que.emplace(to.to, idx, dep + 1);
}
}
auto ret = FastFourierTransform::multiply(num, num);
for(int i = 0; i < ret.size(); i++) dist[i] -= ret[i];
}
auto ret = FastFourierTransform::multiply(cnt, cnt);
for(int i = 0; i < ret.size(); i++) dist[i] += ret[i];
for(auto &to : g.tree.g[centroid]) rec(to);
})(root);
dist.erase(begin(dist));
for(auto &p : dist) p /= 2;
cout << dist << "\n";
}
#line 1 "test/verify/yosupo-frequency-table-of-tree-distance.test.cpp"
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/frequency_table_of_tree_distance
#line 1 "template/template.hpp"
#include<bits/stdc++.h>
using namespace std;
using int64 = long long;
const int mod = 1e9 + 7;
const int64 infll = (1LL << 62) - 1;
const int inf = (1 << 30) - 1;
struct IoSetup {
IoSetup() {
cin.tie(nullptr);
ios::sync_with_stdio(false);
cout << fixed << setprecision(10);
cerr << fixed << setprecision(10);
}
} iosetup;
template< typename T1, typename T2 >
ostream &operator<<(ostream &os, const pair< T1, T2 >& p) {
os << p.first << " " << p.second;
return os;
}
template< typename T1, typename T2 >
istream &operator>>(istream &is, pair< T1, T2 > &p) {
is >> p.first >> p.second;
return is;
}
template< typename T >
ostream &operator<<(ostream &os, const vector< T > &v) {
for(int i = 0; i < (int) v.size(); i++) {
os << v[i] << (i + 1 != v.size() ? " " : "");
}
return os;
}
template< typename T >
istream &operator>>(istream &is, vector< T > &v) {
for(T &in : v) is >> in;
return is;
}
template< typename T1, typename T2 >
inline bool chmax(T1 &a, T2 b) { return a < b && (a = b, true); }
template< typename T1, typename T2 >
inline bool chmin(T1 &a, T2 b) { return a > b && (a = b, true); }
template< typename T = int64 >
vector< T > make_v(size_t a) {
return vector< T >(a);
}
template< typename T, typename... Ts >
auto make_v(size_t a, Ts... ts) {
return vector< decltype(make_v< T >(ts...)) >(a, make_v< T >(ts...));
}
template< typename T, typename V >
typename enable_if< is_class< T >::value == 0 >::type fill_v(T &t, const V &v) {
t = v;
}
template< typename T, typename V >
typename enable_if< is_class< T >::value != 0 >::type fill_v(T &t, const V &v) {
for(auto &e : t) fill_v(e, v);
}
template< typename F >
struct FixPoint : F {
explicit FixPoint(F &&f) : F(forward< F >(f)) {}
template< typename... Args >
decltype(auto) operator()(Args &&... args) const {
return F::operator()(*this, forward< Args >(args)...);
}
};
template< typename F >
inline decltype(auto) MFP(F &&f) {
return FixPoint< F >{forward< F >(f)};
}
#line 4 "test/verify/yosupo-frequency-table-of-tree-distance.test.cpp"
#line 2 "graph/tree/centroid-decomposition.hpp"
#line 2 "graph/graph-template.hpp"
/**
* @brief Graph Template(グラフテンプレート)
*/
template< typename T = int >
struct Edge {
int from, to;
T cost;
int idx;
Edge() = default;
Edge(int from, int to, T cost = 1, int idx = -1) : from(from), to(to), cost(cost), idx(idx) {}
operator int() const { return to; }
};
template< typename T = int >
struct Graph {
vector< vector< Edge< T > > > g;
int es;
Graph() = default;
explicit Graph(int n) : g(n), es(0) {}
size_t size() const {
return g.size();
}
void add_directed_edge(int from, int to, T cost = 1) {
g[from].emplace_back(from, to, cost, es++);
}
void add_edge(int from, int to, T cost = 1) {
g[from].emplace_back(from, to, cost, es);
g[to].emplace_back(to, from, cost, es++);
}
void read(int M, int padding = -1, bool weighted = false, bool directed = false) {
for(int i = 0; i < M; i++) {
int a, b;
cin >> a >> b;
a += padding;
b += padding;
T c = T(1);
if(weighted) cin >> c;
if(directed) add_directed_edge(a, b, c);
else add_edge(a, b, c);
}
}
inline vector< Edge< T > > &operator[](const int &k) {
return g[k];
}
inline const vector< Edge< T > > &operator[](const int &k) const {
return g[k];
}
};
template< typename T = int >
using Edges = vector< Edge< T > >;
#line 4 "graph/tree/centroid-decomposition.hpp"
/**
* @brief Centroid-Decomosition(重心分解)
*/
template< typename T >
struct CentroidDecomposition : Graph< T > {
public:
using Graph< T >::Graph;
using Graph< T >::g;
Graph< int > tree;
int build(int t = 0) {
sub.assign(g.size(), 0);
v.assign(g.size(), 0);
tree = Graph< int >(g.size());
return build_dfs(0);
}
explicit CentroidDecomposition(const Graph< T > &g) : Graph< T >(g) {}
private:
vector< int > sub;
vector< int > v;
inline int build_dfs(int idx, int par) {
sub[idx] = 1;
for(auto &to : g[idx]) {
if(to == par || v[to]) continue;
sub[idx] += build_dfs(to, idx);
}
return sub[idx];
}
inline int search_centroid(int idx, int par, const int mid) {
for(auto &to : g[idx]) {
if(to == par || v[to]) continue;
if(sub[to] > mid) return search_centroid(to, idx, mid);
}
return idx;
}
inline int build_dfs(int idx) {
int centroid = search_centroid(idx, -1, build_dfs(idx, -1) / 2);
v[centroid] = true;
for(auto &to : g[centroid]) {
if(!v[to]) tree.add_directed_edge(centroid, build_dfs(to));
}
v[centroid] = false;
return centroid;
}
};
#line 6 "test/verify/yosupo-frequency-table-of-tree-distance.test.cpp"
#line 1 "math/fft/fast-fourier-transform.hpp"
namespace FastFourierTransform {
using real = double;
struct C {
real x, y;
C() : x(0), y(0) {}
C(real x, real y) : x(x), y(y) {}
inline C operator+(const C &c) const { return C(x + c.x, y + c.y); }
inline C operator-(const C &c) const { return C(x - c.x, y - c.y); }
inline C operator*(const C &c) const { return C(x * c.x - y * c.y, x * c.y + y * c.x); }
inline C conj() const { return C(x, -y); }
};
const real PI = acosl(-1);
int base = 1;
vector< C > rts = { {0, 0},
{1, 0} };
vector< int > rev = {0, 1};
void ensure_base(int nbase) {
if(nbase <= base) return;
rev.resize(1 << nbase);
rts.resize(1 << nbase);
for(int i = 0; i < (1 << nbase); i++) {
rev[i] = (rev[i >> 1] >> 1) + ((i & 1) << (nbase - 1));
}
while(base < nbase) {
real angle = PI * 2.0 / (1 << (base + 1));
for(int i = 1 << (base - 1); i < (1 << base); i++) {
rts[i << 1] = rts[i];
real angle_i = angle * (2 * i + 1 - (1 << base));
rts[(i << 1) + 1] = C(cos(angle_i), sin(angle_i));
}
++base;
}
}
void fft(vector< C > &a, int n) {
assert((n & (n - 1)) == 0);
int zeros = __builtin_ctz(n);
ensure_base(zeros);
int shift = base - zeros;
for(int i = 0; i < n; i++) {
if(i < (rev[i] >> shift)) {
swap(a[i], a[rev[i] >> shift]);
}
}
for(int k = 1; k < n; k <<= 1) {
for(int i = 0; i < n; i += 2 * k) {
for(int j = 0; j < k; j++) {
C z = a[i + j + k] * rts[j + k];
a[i + j + k] = a[i + j] - z;
a[i + j] = a[i + j] + z;
}
}
}
}
vector< int64_t > multiply(const vector< int > &a, const vector< int > &b) {
int need = (int) a.size() + (int) b.size() - 1;
int nbase = 1;
while((1 << nbase) < need) nbase++;
ensure_base(nbase);
int sz = 1 << nbase;
vector< C > fa(sz);
for(int i = 0; i < sz; i++) {
int x = (i < (int) a.size() ? a[i] : 0);
int y = (i < (int) b.size() ? b[i] : 0);
fa[i] = C(x, y);
}
fft(fa, sz);
C r(0, -0.25 / (sz >> 1)), s(0, 1), t(0.5, 0);
for(int i = 0; i <= (sz >> 1); i++) {
int j = (sz - i) & (sz - 1);
C z = (fa[j] * fa[j] - (fa[i] * fa[i]).conj()) * r;
fa[j] = (fa[i] * fa[i] - (fa[j] * fa[j]).conj()) * r;
fa[i] = z;
}
for(int i = 0; i < (sz >> 1); i++) {
C A0 = (fa[i] + fa[i + (sz >> 1)]) * t;
C A1 = (fa[i] - fa[i + (sz >> 1)]) * t * rts[(sz >> 1) + i];
fa[i] = A0 + A1 * s;
}
fft(fa, sz >> 1);
vector< int64_t > ret(need);
for(int i = 0; i < need; i++) {
ret[i] = llround(i & 1 ? fa[i >> 1].y : fa[i >> 1].x);
}
return ret;
}
};
#line 8 "test/verify/yosupo-frequency-table-of-tree-distance.test.cpp"
int main() {
int N;
cin >> N;
CentroidDecomposition< int > g(N);
g.read(N - 1, 0);
int root = g.build();
vector< int > used(N);
vector< int64 > dist(N);
MFP([&](auto rec, int centroid) -> void {
used[centroid] = true;
vector< int > cnt{1};
for(auto &ch : g.g[centroid]) {
if(used[ch]) continue;
vector< int > num;
queue< tuple< int, int, int > > que;
que.emplace(ch, centroid, 1);
while(!que.empty()) {
int idx, par, dep;
tie(idx, par, dep) = que.front();
que.pop();
if(cnt.size() <= dep) cnt.resize(dep + 1, 0);
if(num.size() <= dep) num.resize(dep + 1, 0);
cnt[dep]++;
num[dep]++;
for(auto &to : g.g[idx]) {
if(to == par || used[to]) continue;
que.emplace(to.to, idx, dep + 1);
}
}
auto ret = FastFourierTransform::multiply(num, num);
for(int i = 0; i < ret.size(); i++) dist[i] -= ret[i];
}
auto ret = FastFourierTransform::multiply(cnt, cnt);
for(int i = 0; i < ret.size(); i++) dist[i] += ret[i];
for(auto &to : g.tree.g[centroid]) rec(to);
})(root);
dist.erase(begin(dist));
for(auto &p : dist) p /= 2;
cout << dist << "\n";
}
Env | Name | Status | Elapsed | Memory |
---|---|---|---|---|
g++ | almost_uni_00 | AC | 120 ms | 32 MB |
g++ | almost_uni_01 | AC | 120 ms | 31 MB |
g++ | example_00 | AC | 6 ms | 4 MB |
g++ | line_00 | AC | 666 ms | 51 MB |
g++ | line_star_00 | AC | 467 ms | 47 MB |
g++ | line_star_01 | AC | 375 ms | 46 MB |
g++ | line_star_02 | AC | 467 ms | 47 MB |
g++ | max_random_00 | AC | 241 ms | 32 MB |
g++ | max_random_01 | AC | 244 ms | 32 MB |
g++ | random_00 | AC | 150 ms | 22 MB |
g++ | random_01 | AC | 176 ms | 25 MB |
g++ | random_02 | AC | 63 ms | 11 MB |
g++ | random_03 | AC | 200 ms | 28 MB |
g++ | random_04 | AC | 21 ms | 6 MB |
g++ | small_random_00 | AC | 7 ms | 4 MB |
g++ | small_random_01 | AC | 6 ms | 4 MB |
g++ | small_random_02 | AC | 6 ms | 4 MB |
g++ | small_random_03 | AC | 6 ms | 4 MB |
g++ | small_random_04 | AC | 6 ms | 4 MB |
g++ | uni_00 | AC | 115 ms | 31 MB |
clang++ | almost_uni_00 | AC | 124 ms | 31 MB |
clang++ | almost_uni_01 | AC | 122 ms | 32 MB |
clang++ | example_00 | AC | 6 ms | 4 MB |
clang++ | line_00 | AC | 640 ms | 53 MB |
clang++ | line_star_00 | AC | 450 ms | 48 MB |
clang++ | line_star_01 | AC | 379 ms | 47 MB |
clang++ | line_star_02 | AC | 475 ms | 49 MB |
clang++ | max_random_00 | AC | 244 ms | 32 MB |
clang++ | max_random_01 | AC | 234 ms | 32 MB |
clang++ | random_00 | AC | 143 ms | 22 MB |
clang++ | random_01 | AC | 177 ms | 25 MB |
clang++ | random_02 | AC | 64 ms | 11 MB |
clang++ | random_03 | AC | 199 ms | 28 MB |
clang++ | random_04 | AC | 21 ms | 6 MB |
clang++ | small_random_00 | AC | 6 ms | 4 MB |
clang++ | small_random_01 | AC | 6 ms | 4 MB |
clang++ | small_random_02 | AC | 6 ms | 4 MB |
clang++ | small_random_03 | AC | 6 ms | 4 MB |
clang++ | small_random_04 | AC | 6 ms | 4 MB |
clang++ | uni_00 | AC | 117 ms | 30 MB |