Description
【题目描述】
给出一个n个节点的树,两点之间有且仅有一条路径相连。
给出m个点对xi,yi,如果添加一条双向边边{u,v}后xi和yi在一个简单环中,则称这条边是happy的,happy值为这个简单环的点数。
请你求出对于点对xi,yi,所有happy的边的happy值的平均数。
注意,出题人似乎认为简单环是包括自环的。
【输入数据】
第一行2个整数n,m;
接下来n-1行,每行两个整数x,y表示在树中x,y有一条双向边相连;
接下来m行,每行2个整数xi,yi表示询问点对。
【输出数据】
对于每个询问的点对,输出一个实数表示所有happy的边的happy值的平均数,结果保留7位小数。
【样例输入1】
4 3
2 4
4 1
3 2
3 1
2 3
4 1
【样例输出1】
4.0000000
3.0000000
3.0000000
【样例输入2】
3 3
1 2
1 3
1 2
1 3
2 3
【样例输出2】
2.5000000
2.5000000
3.0000000
【样例解释】
在样例2中:对于第一个询问,边{1,2}和边{2,3}都是happy的,happy值分别为2,3,ans=(2+3)/2
对于第二个询问,边{1,3}和边{2,3}都是happy的,happy值分别为2,3,ans=(2+3)/2
对于第三个询问,只有边{2,3}是happy的,happy值为3,ans=3/1
【数据范围】
对于20%的数据满足:n<=100,m<=100;
对于100%的数据满足:n<=100000,m<=100000。
思路
单独考虑每个点对答案的贡献
统计一下子树内的
还有统计上面的
所以正着dfs一遍,倒着dfs一遍即可
代码
#include<bits/stdc++.h>
#define ll long long
#define N 100077
using namespace std;
ll n,m,fa[N][17],dep[N],ls[N],v[N<<1],nx[N<<1],cnt=0,siz[N],ans1[N],ans2[N];
double ans[N];
void add(ll s,ll e)
{
cnt++;v[cnt]=e;nx[cnt]=ls[s];ls[s]=cnt;
cnt++;v[cnt]=s;nx[cnt]=ls[e];ls[e]=cnt;
}
void dfs1(ll u,ll f)
{
siz[u]=1;
fa[u][0]=f;
for(ll i=1; i<=16; i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(ll i=ls[u]; i; i=nx[i])
if(v[i]^f)
{
dep[v[i]]=dep[u]+1;
dfs1(v[i],u);
siz[u]+=siz[v[i]];
}
}
void go_up(ll &k,ll d)
{
for(ll i=16; i>=0;--i)
if(d&(1<<i))k=fa[k][i];
}
ll LCA(ll a,ll b)
{
if(dep[a]>dep[b])go_up(a,dep[a]-dep[b]);
if(dep[a]<dep[b])go_up(b,dep[b]-dep[a]);
if(a==b)return a;
for(ll i=16; i>=0;--i)
if(fa[a][i]!=fa[b][i])
{
a=fa[a][i];
b=fa[b][i];
}
return fa[a][0];
}
void dfs2(ll u,ll f)
{
ans1[u]=dep[u];
for(ll i=ls[u]; i; i=nx[i])
if(v[i]^f)
{
ans2[v[i]]=ans2[u]-siz[v[i]]+(n-siz[v[i]]);
dfs2(v[i],u);
ans1[u]+=ans1[v[i]];
}
}
void dfs3(ll u,ll f)
{
ll sum1=1,sum2=0;
for(ll i=ls[u]; i; i=nx[i])
if(v[i]^f)
{
sum1+=1ll*siz[v[i]]*(n-siz[v[i]]);
sum2+=(ans1[v[i]]-1ll*siz[v[i]]*dep[u])*(n-siz[v[i]]);
}
if(f)
{
sum1+=1ll*(n-siz[u])*siz[u];
sum2+=(ans2[u]-(ans1[u]-1ll*dep[u]*siz[u]))*siz[u];
}
sum1+=n;
sum1/=2;
ans[u]=1.0*sum2/sum1+1.0;
for(ll i=ls[u]; i; i=nx[i])
if(v[i]^f)
dfs3(v[i],u);
}
int main()
{
scanf("%lld%lld",&n,&m);
ll s,e;
for(ll i=1; i<n; i++)
{
scanf("%lld%lld",&s,&e);
add(s,e);
}
dfs1(1,0);
for(ll i=1; i<=n; i++)ans2[1]+=dep[i];
dfs2(1,0);
dfs3(1,0);
ll x,y;
for(ll i=1; i<=m; i++)
{
scanf("%lld%lld",&x,&y);
if(x==y)printf("%.7lf\n",ans[x]);
else
{
ll lca=LCA(x,y);
ll sum1=0,sum2=0;
if(x==lca||y==lca)
{
if(x!=lca)swap(x,y);
ll d=y;
go_up(d,dep[y]-dep[x]-1);
sum1=1ll*(n-siz[d])*siz[y];
sum2+=1ll*(ans1[y]-1ll*siz[y]*dep[y])*(n-siz[d]);
sum2+=(ans2[x]-(ans1[d]-1ll*siz[d]*dep[x]))*siz[y];
double res=1.0*sum2/sum1;
res+=1.0;
res+=dep[y]-dep[x];
printf("%.7lf\n",res);
}
else
{
sum1=1ll*siz[x]*siz[y];
sum2+=(ans1[x]-1ll*siz[x]*dep[x])*siz[y];
sum2+=(ans1[y]-1ll*siz[y]*dep[y])*siz[x];
double res=1.0*sum2/sum1;
res+=1.0;
res+=dep[x]+dep[y]-2*dep[lca];
printf("%.7lf\n",res);
}
}
}
}