LA 6534 Join two kingdoms 树的直径+twopoint

来源:互联网 发布:云计算运用有哪些 编辑:程序博客网 时间:2024/06/05 15:12

题意:给定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;}


0 0