Description:
每次点分治随机选重心,问期望复杂度。
Solution:
每次点分的复杂度可以看成和重心形成的点对数量,那么
u
u
为重心时和形成点对的概率是
1dis(u,v)+1
1
d
i
s
(
u
,
v
)
+
1
。意思是
u
u
到路径上之前没有点被选为重心,答案即为
∑ni=1∑nj=11dis(i,j)+1
∑
i
=
1
n
∑
j
=
1
n
1
d
i
s
(
i
,
j
)
+
1
套用点分治,利用生成函数统计点对距离与数量即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const double pi = acos(-1);
struct cp {
double x, y;
cp() {}
cp(double _x, double _y) : x(_x), y(_y) {}
cp friend operator + (const cp &a, const cp &b) {
return cp(a.x + b.x, a.y + b.y);
}
cp friend operator - (const cp &a, const cp &b) {
return cp(a.x - b.x, a.y - b.y);
}
cp friend operator * (const cp &a, double b) {
return cp(a.x * b, a.y * b);
}
cp friend operator * (const cp &a, const cp &b) {
return cp(a.x * b.x - a.y * b.y, a.y * b.x + a.x * b.y);
}
} a[maxn];
int n, N, len, rt;
double ans;
int vis[maxn], mx[maxn], sz[maxn], dep[maxn];
vector<int> G[maxn];
void fft(cp *a, int f) {
for(int i = 0; i < n; ++i) {
int t = 0;
for(int j = 0; j < len; ++j) {
if(i >> j & 1) {
t |= 1 << (len - j - 1);
}
}
if(i < t) {
swap(a[i], a[t]);
}
}
for(int l = 2; l <= n; l <<= 1) {
int m = l >> 1;
cp w = cp(cos(pi / m), f * sin(pi / m));
for(int i = 0; i < n; i += l) {
cp t = cp(1, 0);
for(int k = 0; k < m; ++k, t = t * w) {
cp x = a[i + k], y = t * a[i + m + k];
a[i + k] = x + y;
a[i + m + k] = x - y;
}
}
}
if(f == -1)
for(int i = 0; i < n; ++i) {
a[i].x /= n;
}
}
void dfs(int u, int last) {
n = max(n, dep[u]);
++a[dep[u]].x;
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(v == last || vis[v]) {
continue;
}
dep[v] = dep[u] + 1;
dfs(v, u);
}
}
int getsize(int u, int last) {
int ret = 1;
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(v == last || vis[v]) {
continue;
}
ret += getsize(v, u);
}
return ret;
}
void getroot(int u, int last, int S) {
sz[u] = 1;
mx[u] = 0;
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(vis[v] || v == last) {
continue;
}
getroot(v, u, S);
mx[u] = max(mx[u], sz[v]);
sz[u] += sz[v];
}
mx[u] = max(mx[u], S - sz[u]);
if(mx[u] < mx[rt]) {
rt = u;
}
}
void calc(int tmp, double f) {
for(n = 1, len = 0; n <= 2 * tmp; n <<= 1){
++len;
}
fft(a, 1);
for(int i = 0; i < n; ++i) {
a[i] = a[i] * a[i];
}
fft(a, -1);
for(int i = 0; i < n; ++i) {
ans += (double)f * a[i].x / (double)(i + 1);
}
for(int i = 0; i < n; ++i) {
a[i] = cp(0, 0);
}
n = 0;
}
void solve(int u) {
dep[u] = 0;
dfs(u, 0);
calc(n, 1);
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(vis[v]) {
continue;
}
dep[v] = 1;
dfs(v, 0);
calc(n, -1);
}
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(vis[v]) {
continue;
}
rt = 0;
getroot(v, 0, getsize(v, 0));
vis[rt] = 1;
solve(rt);
}
}
int main() {
scanf("%d", &N);
for(int i = 1; i < N; ++i) {
int u, v;
scanf("%d%d", &u, &v);
++u;
++v;
G[u].push_back(v);
G[v].push_back(u);
}
mx[0] = 0x3f3f3f3f;
getroot(1, 0, N);
vis[rt] = 1;
solve(rt);
printf("%.4f\n", ans);
return 0;
}