http://www.lydsy.com/JudgeOnline/problem.php?id=3451
一个点对于答案的贡献就是他在点分树上的深度
对于一个点对\(u, v\)
\(u\) 对 \(v\) 有贡献当且仅当在\(u\) -> \(v\)路径上先选了\(u\)
由于路径上的点被选到的概率相同
答案就是
\[\sum_{i=1}^{n}\sum_{j=1}^{n}\frac{1}{dis(i, j)}\]
然后点分治FFT就好了
复杂度\(O(n\; {\log n}^2)\)
#include<bits/stdc++.h>
#define lb long double
#define fo(i, n) for(int i = 1; i <= (n); i ++)
#define out(x) cerr << #x << " = " << x << "\n"
#define type(x) __typeof((x).begin())
#define foreach(it, x) for(type(x) it = (x).begin(); it != (x).end(); ++ it)
using namespace std;
// by piano
template<typename tp> inline void read(tp &x) {
x = 0; char c = getchar(); bool f = 0;
for(; c < '0' || c > '9'; f |= (c == '-'), c = getchar());
for(; c >= '0' && c <= '9'; x = (x << 3) + (x << 1) + c - '0', c = getchar());
if(f) x = -x;
}
template<typename tp> inline void arr(tp *a, int n) {
for(int i = 1; i <= n; i ++)
cout << a[i] << " ";
puts("");
}
const int N = 3e4 + 233;
const int M = N;
int ans[N];
namespace FFT {
const int N = 3e5 + 233;
const lb pi = acos(-1.0);
struct cpx {
lb a, b;
cpx(lb _a = 0, lb _b = 0) {
a = _a; b = _b;
}
}a[N];
cpx operator + (const cpx &a, const cpx &b) {
return cpx(a.a + b.a, a.b + b.b);
}
cpx operator - (const cpx &a, const cpx &b) {
return cpx(a.a - b.a, a.b - b.b);
}
cpx operator * (const cpx &a, const cpx &b) {
return cpx(a.a * b.a - a.b * b.b, a.a * b.b + a.b * b.a);
}
int n, rev[N], x, L = -1;
inline void fft(cpx *a, int fff) {
for(int i = 0; i < n; i ++) if(i < rev[i]) swap(a[i], a[rev[i]]);
for(int l = 2; l <= n; l <<= 1) {
cpx wn = cpx(cos(2 * pi / l), sin(2 * pi / l * fff));
for(int j = 0, m = l >> 1; j < n; j += l) {
cpx w(1, 0);
for(int k = 0; k < m; k ++, w = w * wn) {
cpx x = a[j + k], y = w * a[j + k + m];
a[j + k] = x + y;
a[j + k + m] = x - y;
}
}
}
if(fff == -1) {
for(int i = 0; i < n; i ++)
a[i].a /= n;
}
}
inline void init(int m) {
L = -1;
for(n = 1; n <= m + 1; n <<= 1) L ++;
memset(a, 0, sizeof(cpx) * (n + 2));
for(int i = 0; i < n; i ++)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
}
inline void U(int pos, int val) {
a[pos].a += val;
}
inline void doit(int fff) {
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[i] = ans[i] + fff * ((int) (a[i].a + 0.5));
}
}
struct E {
int nxt, to;
}e[M << 1];
int head[N], e_cnt = 0;
int f[N], sz[N], rt = 0, all, dep[N], book[N];
int n, m;
inline void add(int u, int v) {
e[++ e_cnt] = (E) {head[u], v}; head[u] = e_cnt;
}
inline void frt(int u, int fat) {
f[u] = 0; sz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fat || book[v]) continue;
frt(v, u);
sz[u] += sz[v];
f[u] = max(f[u], sz[v]);
}
f[u] = max(f[u], all - sz[u]);
if(!rt || f[rt] > f[u]) rt = u;
}
vector<int> vec;
inline void dfs(int u, int fat) {
vec.push_back(dep[u] = dep[fat] + 1);
FFT::U(dep[u], 1);
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fat || book[v]) continue;
dfs(v, u);
}
}
inline void cal(int u, int fff, int init) {
vec.clear();
int now = sz[u];
FFT::init(now * 2);
dep[0] = init - 1;
dfs(u, 0);
FFT::doit(fff);
}
inline void work(int u, int fat) {
book[u] = 1; cal(u, 1, 0);
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(v == fat || book[v]) continue;
cal(v, -1, 1);
all = sz[v];
frt(v, rt = 0);
work(rt, u);
}
}
inline void doit(void) {
lb res = 0;
for(int i = 0; i <= n; i ++)
res += ans[i] * 1.0 / (i + 1);
printf("%.4f\n", (double)res);
}
main(void) {
read(n);
for(int i = 1; i <= n - 1; i ++) {
int x, y; read(x); read(y);
++ x; ++ y;
add(x, y); add(y, x);
}
all = n;
frt(1, rt = 0);
work(rt, 0);
doit();
}