太久之前写的都快忘了= = 这题做起来还是挺简单的。当时很快就想出来写完了(调好久我会乱说嘛)
题意即
给你一个森林,每次询问给出u,v,
从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,
问你此时相连出的树的直径期望是多少?(如果本身就在同一个连通块内,则输出-1)
仔细想一下就知道答案只有两种情况,大树的直径或两个树链接起来。
求每个连通块直径后从两端点找到最长的一个距离。
然后因为答案只有那两种情况 考虑如何算期望。就是一个点会等概率匹配所有点,可以按长度算后缀和后我记得是
O(n)
O
(
n
)
扫一遍计算答案。
= =总之这题就是个暴力思路很好想 大力码代码就好了
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e5+5;
typedef pair<int,int>par;
#define mp make_pair
#define ll long long
struct edge{
ll to,next,w;
}e[MAXN<<1];
ll head[MAXN],cnt=0;
inline void add(ll u,ll v){
e[++cnt]=(edge){v,head[u]},head[u]=cnt;
e[++cnt]=(edge){u,head[v]},head[v]=cnt;
}
map<par,double>ma;
ll n,m,q,belong[MAXN],tim=0;
bool vis[MAXN],vis2[MAXN];
struct data{
ll maxdis;
vector<ll>dissum,dissz;
}d[MAXN];
ll who=0,whodis=0;
ll s[MAXN],top=0,dist[MAXN][4],ly;
void dfs(ll u,ll fa,ll dis){
if(dis>whodis)whodis=dis,who=u;
s[++top]=u;
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa)continue;
dfs(v,u,dis+1);
}
}
void dfs2(ll u,ll fa,ll num){
if(dist[u][num]>whodis)whodis=dist[u][num],who=u;
if(num==2)dist[u][3]=max(dist[u][1],dist[u][2]),ly=max(ly,dist[u][3]);
for(ll i=head[u];i;i=e[i].next){
ll v=e[i].to;
if(v==fa)continue;
dist[v][num]=dist[u][num]+1;
dfs2(v,u,num);
}
}
void get(ll x){
who=x;whodis=0;top=0,ly=0;
dfs(x,x,0);
ll l=who;whodis=0;dist[l][1]=0;
dfs2(l,l,1);ll r=who;dist[r][2]=0;
dfs2(r,r,2);++tim;
for(ll i=0;i<=ly+1;i++)d[tim].dissum.push_back(0),d[tim].dissz.push_back(0);
d[tim].maxdis=ly;
// for(ll i=top;i;i--)cout<<s[i]<<":"<<dist[s[i]][3]<<"ok"<<endl;
// cout<<endl;
for(ll i=top;i;i--)belong[s[i]]=tim,d[tim].dissz[dist[s[i]][3]]+=1,d[tim].dissum[dist[s[i]][3]]+=dist[s[i]][3];//后缀和
for(ll i=ly;i>=1;i--)d[tim].dissz[i-1]+=d[tim].dissz[i],d[tim].dissum[i-1]+=d[tim].dissum[i];
// for(ll i=0;i<=ly+1;i++)cout<<d[tim].dissz[i]<<" ";cout<<endl;
// for(ll i=0;i<=ly+1;i++)cout<<d[tim].dissum[i]<<" ";cout<<endl;
}
double solve(ll a,ll b){//a是大块 b是小块
ll ans=0;
ll maxlen=d[a].maxdis;
ll minlen=d[b].maxdis;
if(maxlen==0)return 1.0;
for(ll i=maxlen;i>=maxlen-1;i--){
ans+=((i+1)*d[b].dissz[0]+d[b].dissum[0])*(d[a].dissz[i]-d[a].dissz[i+1]);
}
ll where=0,where2=maxlen-1,flag=0;
//if(a==1&&b==4)cout<<maxlen<<" "<<minlen<<"okok"<<endl;
for(ll i=maxlen-2;i>=1;i--){
flag=1;
where2--;++where;if(where>minlen)break;
//ans+=(d[a].dissum[i]-d[a].dissum[i+1])*d[b].dissz[where]+d[b].dissum[where]+d[b].dissz[where]*(d[a].dissz[i]-d[a].dissz[i+1]);
// cout<<(d[a].dissz[i]-d[a].dissz[i+1])<<"orztata momomo";
ans+=((i+1)*d[b].dissz[where]+d[b].dissum[where])*(d[a].dissz[i]-d[a].dissz[i+1]);
ans+=maxlen*(d[b].dissz[0]-d[b].dissz[where])*(d[a].dissz[i]-d[a].dissz[i+1]) ;
//cout<<(d[b].dissz[0]-d[b].dissz[where])<<"orzd2 momomo";
// cout<<ans<<"ok";
}
// cout<<ans<<"ok";
// cout<<where2<<"ok";
if(flag)ans+=maxlen*(d[a].dissz[0]-d[a].dissz[where2+1])*d[b].dissz[0];
// cout<<(double)ans/(d[a].dissz[0]*d[b].dissz[0]);
return (double)ans/(d[a].dissz[0]*d[b].dissz[0]);
}
int main(){
scanf("%I64d%I64d%I64d",&n,&m,&q);
for(ll i=1;i<=m;i++){
ll u,v;
scanf("%I64d%I64d",&u,&v);
add(u,v);
}
for(ll i=1;i<=q;i++){
ll u,v;
scanf("%I64d%I64d",&u,&v);
if(!belong[u])get(u);if(!belong[v])get(v);
ll a=belong[u],b=belong[v];
if(a!=b){
if(d[a].maxdis<d[b].maxdis)swap(a,b);
if(!ma[mp(a,b)]){
ma[mp(a,b)]=solve(a,b);
}
printf("%.10lf\n",ma[mp(a,b)]);
}
else printf("-1\n");
}
return 0;
}