LA 6534 Join two kingdoms 樹的直徑+twopoint

題意:給定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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章