题意:随机分治中心点分治的期望操作次数
n≤3×104n\leq 3\times 10^4n≤3×104
即求点分树的 siz 之和的期望
即祖孙关系对数期望
考虑一有序点对 (u,v)(u,v)(u,v),uuu 在点分树上是 vvv 祖先当且仅当 uuu 是 u∼vu\sim vu∼v 路径上第一个被选为分治中心的,并且选择路径外的点是不影响的,所以概率为 1dist(u,v)+1\dfrac 1{\operatorname{dist}(u,v)+1}dist(u,v)+11
由期望线性性,答案为
∑i=1n∑j=1n1dist(i,j)+1\sum_{i=1}^n\sum_{j=1}^{n}\frac 1{\operatorname{dist}(i,j)+1}i=1∑nj=1∑ndist(i,j)+11
相当于是求距离为 0∼n−10\sim n-10∼n−1 的点对数量,考虑点分治
计算当前答案时发现是个卷积形式,使用 NTT 优化
算出整个连通块的答案,然后容斥掉在同一个子树中的
因为深度是不会超过大小的,所以复杂度为 O(nlog2n)O(n\log ^2n)O(nlog2n)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <vector>
#define MAXN 65536
using namespace std;
const int MOD=998244353;
inline int add(const int& x,const int& y){return x+y>=MOD? x+y-MOD:x+y;}
inline int dec(const int& x,const int& y){return x<y? x-y+MOD:x-y;}
typedef long long ll;
inline int qpow(int a,int p)
{int ans=1;while (p){if (p&1) ans=(ll)ans*a%MOD;a=(ll)a*a%MOD,p>>=1;}return ans;
}
#define inv(x) qpow(x,MOD-2)
int rt[2][24];
int l,lim,r[MAXN];
inline void init(){lim=1<<l;for (int i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));}
inline void NTT(int* a,int type)
{for (int i=0;i<lim;i++) if (i<r[i]) swap(a[i],a[r[i]]);for (int L=0;L<l;L++){int mid=1<<L,len=mid<<1;ll Wn=rt[type][L+1];for (int s=0;s<lim;s+=len)for (int k=0,w=1;k<mid;k++,w=w*Wn%MOD){int x=a[s+k],y=(ll)w*a[s+mid+k]%MOD;a[s+k]=add(x,y),a[s+mid+k]=dec(x,y);}}if (type){int t=inv(lim);for (int i=0;i<lim;i++) a[i]=(ll)a[i]*t%MOD;}
}
inline double calc(int* a,int n)
{double ans=0;for (l=0;(1<<l)<=(n<<1);++l);init(),NTT(a,0);for (int i=0;i<lim;i++) a[i]=(ll)a[i]*a[i]%MOD;NTT(a,1);for (int i=0;i<lim;i++){ans+=(double)a[i]/(i+1);a[i]=0;}return ans;
}
vector<int> e[MAXN];
double ans;
bool vis[MAXN];
int siz[MAXN],maxp[MAXN]={0x7fffffff},Rt;
int a[MAXN];
void findrt(int u,int f,int sum)
{siz[u]=1,maxp[u]=0;for (int i=0;i<(int)e[u].size();i++)if (e[u][i]!=f&&!vis[e[u][i]]){findrt(e[u][i],u,sum);siz[u]+=siz[e[u][i]];maxp[u]=max(maxp[u],siz[e[u][i]]);}maxp[u]=max(maxp[u],sum-siz[u]);if (maxp[u]<maxp[Rt]) Rt=u;
}
int dfs(int u,int f,int dep)
{siz[u]=1,++a[dep];int mx=dep;for (int i=0;i<(int)e[u].size();i++)if (e[u][i]!=f&&!vis[e[u][i]]){mx=max(mx,dfs(e[u][i],u,dep+1));siz[u]+=siz[e[u][i]];}return mx;
}
inline void calc()
{ans+=calc(a,dfs(Rt,0,0));for (int i=0;i<(int)e[Rt].size();i++)if (!vis[e[Rt][i]])ans-=calc(a,dfs(e[Rt][i],0,1));
}
void solve()
{int u=Rt;vis[u]=1;calc();for (int i=0;i<(int)e[u].size();i++)if (!vis[e[u][i]]){int v=e[u][i];Rt=0,findrt(v,0,siz[v]);solve();}
}
int main()
{rt[0][23]=qpow(3,119),rt[1][23]=inv(rt[0][23]);for (int i=22;i>=0;i--){rt[0][i]=(ll)rt[0][i+1]*rt[0][i+1]%MOD;rt[1][i]=(ll)rt[1][i+1]*rt[1][i+1]%MOD;}int n;scanf("%d",&n);for (int i=1;i<n;i++){int u,v;scanf("%d%d",&u,&v);++u,++v;e[u].push_back(v),e[v].push_back(u);}findrt(1,0,n);solve();printf("%.4f\n",ans);return 0;
}