tyvj1953 Normal

时间:2023-03-09 15:54:24
tyvj1953 Normal

题目链接

正解:点分治+$FFT$。

很想吐槽一下$bzoj$,为什么搬了别的$oj$的题还设成权限题。。

首先我们考虑期望的线性性,即考虑每个点的贡献。

显然每个点的贡献就是它在点分树上的深度,所以我们进一步考虑哪些点在它到根的路径上。

我们考虑每一条路径的贡献,显然对于一条路径$(x,y)$,当且仅当$x$是路径上最浅的点时会对$y$有$1$的贡献。

那么这条路径$x$深度最浅的概率,实际上就是$\frac{1}{len(x,y)}$,因为每个点作为深度最浅的点的概率相等。

所以我们统计每一种长度的路径个数就行了,这个用$FFT$即可解决。

 #include <bits/stdc++.h>
#define il inline
#define RG register
#define ll long long
#define N (1000005) using namespace std; struct edge{ int nt,to; }g[N];
struct C{
double x,y;
il C operator + (const C &a) const{
return (C){x+a.x,y+a.y};
}
il C operator - (const C &a) const{
return (C){x-a.x,y-a.y};
}
il C operator * (const C &a) const{
return (C){x*a.x-y*a.y,x*a.y+y*a.x};
}
}a[N]; const double pi=acos(-1.0); int head[N],vis[N],dis[N],son[N],sz[N],rev[N],n,num,len,Max;
double ans[N],Ans; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-'',ch=getchar();
return q*x;
} il void insert(RG int from,RG int to){
g[++num]=(edge){head[from],to},head[from]=num; return;
} il void fft(C *a,RG int n,RG int f){
for (RG int i=;i<n;++i) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (RG int i=;i<n;i<<=){
C wn=(C){cos(pi/i),sin(f*pi/i)};
for (RG int j=;j<n;j+=i<<){
C w=(C){,},x,y;
for (RG int k=;k<i;++k,w=w*wn){
x=a[j+k],y=w*a[j+k+i];
a[j+k]=x+y,a[j+k+i]=x-y;
}
}
}
if (f==-) for (RG int i=;i<len;++i) a[i].x/=n; return;
} il void getrt(RG int x,RG int p,RG int &rt){
son[x]=,sz[x]=;
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v==p || vis[v]) continue;
getrt(v,x,rt),sz[x]+=sz[v],son[x]=max(son[x],sz[v]);
}
son[x]=max(son[x],son[]-sz[x]);
if (son[rt]>=son[x]) rt=x; return;
} il void getdis(RG int x,RG int p){
sz[x]=,++a[dis[x]].x,Max=max(Max,dis[x]);
for (RG int i=head[x],v;i;i=g[i].nt){
v=g[i].to; if (v==p || vis[v]) continue;
dis[v]=dis[x]+,getdis(v,x),sz[x]+=sz[v];
}
return;
} il void calc(RG int rt,RG int lim,RG int fg){
Max=,dis[rt]=lim,getdis(rt,); RG int lg=;
for (len=;len<=(Max<<);len<<=) ++lg;
for (RG int i=;i<len;++i) rev[i]=rev[i>>]>>|((i&)<<(lg-));
fft(a,len,); for (RG int i=;i<len;++i) a[i]=a[i]*a[i]; fft(a,len,-);
for (RG int i=;i<len;++i) ans[i]+=(ll)(a[i].x+0.5)*fg,a[i]=(C){,}; return;
} il void solve(RG int x,RG int S){
RG int rt=; son[]=S,getrt(x,,rt);
vis[rt]=,calc(rt,,);
for (RG int i=head[rt];i;i=g[i].nt)
if (!vis[g[i].to]) calc(g[i].to,,-);
for (RG int i=head[rt];i;i=g[i].nt)
if (!vis[g[i].to]) solve(g[i].to,sz[g[i].to]);
return;
} int main(){
#ifndef ONLINE_JUDGE
freopen("normal.in","r",stdin);
freopen("normal.out","w",stdout);
#endif
n=gi();
for (RG int i=,u,v;i<n;++i)
u=gi()+,v=gi()+,insert(u,v),insert(v,u);
solve(,n);
for (RG int i=;i<n;++i) Ans+=1.0*ans[i]/(i+);
printf("%0.4lf\n",Ans); return ;
}