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; }