codeforces805F Expected diameter of a tree

题目大意:

给定一个森林,有若干个询问,每次询问在第i棵树中随机选一个点,在第j棵树中随机选一个点并将它们相连后树的直径的期望值。

 

对每棵树求出它的直径d,对每个点求出它到树上最远点的距离f,那么选择x、y点时树的直径就是:

max(d[i],d[j],f[x]+f[y]+1)

对每棵树中点的f排序。

枚举一棵树中每个点,再二分另一棵树的f就能统计答案了。

具体看代码。

 

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
#define ll long long
#define N 100010
vector<int>g[N],e[N];
vector<ll>Sum[N];
map<int,double>M[N];
int f[N],i,j,n,m,x,y,Q,s[N],d[N],a[N],Ma,Y;
bool Flag;
double Ans,k;
inline int Max(int x,int y){return x<y?y:x;}
inline int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
inline void Dfs1(int x,int p,int s){
    if(Flag)return;
    if(d[x]){Flag=1;return;}
    if(s>Ma)Ma=s,y=x;
    d[x]=Max(d[x],s);
    for(int i=0;i<e[x].size();i++)
    if(e[x][i]!=p)Dfs1(e[x][i],x,s+1);
}
inline void Dfs2(int x,int p,int s){
    if(s>Ma)Ma=s,y=x;
    d[x]=Max(d[x],s);
    for(int i=0;i<e[x].size();i++)
    if(e[x][i]!=p)Dfs2(e[x][i],x,s+1);
}
inline bool Calc(int x){
    Flag=0;Ma=-1;
    Dfs1(x,0,0);
    if(Flag)return 1;
    Ma=-1;
    Dfs2(y,0,0);
    Dfs2(y,0,0);
    return 0;
}
inline int Binary(int x,int y){
    if(g[x][0]>=y)return -1;
    if(g[x][g[x].size()-1]<=y)return g[x].size()-1;
    int l=0,r=g[x].size()-2,Mid;
    while(l<=r){
        Mid=l+r>>1;
        if(g[x][Mid]<=y&&g[x][Mid+1]>=y)return Mid;
        if(g[x][Mid]>y)r=Mid-1;else l=Mid+1;
    }
    return l;
}
int main(){
    scanf("%d%d%d",&n,&m,&Q);
    for(i=1;i<=n;i++)f[i]=i;
    for(i=1;i<=m;i++)scanf("%d%d",&x,&y),f[Find(x)]=Find(y),e[x].push_back(y),e[y].push_back(x);
    for(i=1;i<=n;i++){
        if(Find(i)==i&&Calc(i))a[i]=-1;
        s[f[i]]++;
    }
    for(i=1;i<=n;i++)
    if(a[f[i]]!=-1)a[f[i]]=Max(a[f[i]],d[i]),g[f[i]].push_back(d[i]);
    for(i=1;i<=n;i++)
    if(s[i]&&a[i]!=-1){
        sort(g[i].begin(),g[i].end());
        Sum[i].push_back(g[i][0]);
        for(j=1;j<g[i].size();j++)Sum[i].push_back(Sum[i][j-1]+g[i][j]);
    }
    while(Q--){
        scanf("%d%d",&x,&y);
        x=Find(x);y=Find(y);
        if(x==y||a[x]==-1||a[y]==-1){puts("-1");continue;}
        if(s[x]>s[y]||(s[x]==s[y]&&x>y))swap(x,y);
        k=M[x][y];
        if(k){printf("%.9lf\n",k);continue;}
        Ma=Max(a[x],a[y]);Y=g[y].size();
        for(i=Ans=0;i<g[x].size();i++){
            j=Binary(y,Ma-g[x][i]-1);
            if(j>-1)Ans+=1ll*Ma*(j+1);
            if(j<Y-1)Ans+=Sum[y][Y-1]-(j>-1?Sum[y][j]:0)+1ll*(Y-j-1)*(g[x][i]+1);
        }
        Ans/=1ll*s[x]*s[y];
        M[x][y]=Ans;
        printf("%.9lf\n",Ans);
    }
    return 0;
}
codeforces805F

 

posted @ 2017-05-25 20:45  gjghfd  阅读(180)  评论(0编辑  收藏  举报