題意:給定n,m分別表示兩棵樹的大小
第一棵樹的n-1條邊,第二棵樹的m-1條邊
求用一條邊將兩棵樹連接起來構成的樹的直徑的期望。
思路:先分別求出兩棵樹的直徑,然後預處理求出從每個樹上的點可到達的最長距離。接下來枚舉各樹的一個點,累加這種情況下的
樹的直徑(要與兩棵樹本身的直徑去比較大小,取較大值),最後除以nm,就是期望,但是這樣的複雜度爲O(n^2)。所以我們可以排
序,然後利用twopoint,將複雜度降爲O(n)。詳見代碼:
/*********************************************************
file name: LA6534.cpp
author : kereo
create time: 2015年02月07日 星期六 17時55分24秒
*********************************************************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<cmath>
#include<string>
#include<algorithm>
using namespace std;
typedef long long ll;
const int sigma_size=26;
const int N=100+50;
const int MAXN=40000+50;
const int inf=0x3fffffff;
const double eps=1e-8;
const int mod=1000000000+7;
#define L(x) (x<<1)
#define R(x) (x<<1|1)
#define PII pair<int, int>
#define mk(x,y) make_pair((x),(y))
int n,m;
int l1[MAXN],l2[MAXN];
ll sum[MAXN];
struct Node{
int edge_cnt,l,top;
int head[MAXN],d[MAXN],fa[MAXN],vis[MAXN],s[MAXN],dp[MAXN];
struct Edge{
int v,next;
}edge[MAXN<<1];
void init(){
edge_cnt=top=0;
memset(head,-1,sizeof(head));
}
void addedge(int u,int v){
edge[edge_cnt].v=v;
edge[edge_cnt].next=head[u]; head[u]=edge_cnt++;
}
int bfs(int st){
int ans=st;
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(st);
vis[st]=1; d[st]=0; fa[st]=-1;
while(!Q.empty()){
int u=Q.front(); Q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(vis[v])
continue;
vis[v]=1;
d[v]=d[u]+1; fa[v]=u;
if(d[v]>d[ans])
ans=v;
Q.push(v);
}
}
return ans;
}
void dfs(int u){
for(int i=head[u];i!=-1;i=edge[i].next){
int v=edge[i].v;
if(vis[v])
continue;
vis[v]=1; dp[v]=dp[u]+1;
dfs(v);
}
}
void solve(){
int st=bfs(1);
int ed=bfs(st);
l=d[ed];
memset(vis,0,sizeof(vis));
int u=ed;
while(u!=-1){
vis[u]=1;
dp[u]=max(d[u],l-d[u]);
s[top++]=u;
u=fa[u];
}
for(int i=0;i<top;i++){
int u=s[i];
dfs(u);
}
}
}X,Y;
int main(){
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m)){
X.init(); Y.init();
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
X.addedge(u,v); X.addedge(v,u);
}
for(int i=1;i<m;i++){
int u,v;
scanf("%d%d",&u,&v);
Y.addedge(u,v); Y.addedge(v,u);
}
X.solve(); Y.solve();
int len=max(X.l,Y.l);
for(int i=1;i<=n;i++)
l1[i]=X.dp[i]+1;
for(int i=1;i<=m;i++)
l2[i]=Y.dp[i];
sort(l1+1,l1+n+1);
sort(l2+1,l2+m+1);
int index=m+1;
double ans=0;
sum[0]=0;
for(int i=1;i<=m;i++)
sum[i]=sum[i-1]+l2[i];
for(int i=1;i<=n;i++){
while(index-1>=1 && l1[i]+l2[index-1]>=len)
index--;
if(index == 1)
ans+=sum[m]+m*l1[i];
else if(index == m+1)
ans+=(double)len*m;
else{
ans+=(double)len*(index-1);
ans+=sum[m]-sum[index-1]+(double)(m-index+1)*l1[i];
}
}
printf("%.3f\n",ans/n/m);
}
return 0;
}