codeforces804D Expected diameter of a tree
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:codeforces804D
正解:二分$+DP$
解题报告:
预处理出每个点所在的树内的最远点距离dis,考虑对于树$A$的点$x$,与树$B$的$y$产生的贡献就是$dis[x]+dis[y]+1$和两棵树的直径取一个$max$。
对于$max$,我们显然可以分开考虑,当$dis[x]+dis[y]+1<$两棵树的直径,那么贡献就是直径的$max$。
否则我们可以直接得到贡献。
具体做法就是先对于每棵树内部的$dis$排序,然后每次枚举较小的连通块内的每个点,二分另一个连通块中的分界点位置就好了。
看上去像个暴力,但是仔细想想,套上记忆化之后复杂度应该很靠谱,大概是根号左右。
//It is made by ljh2000 #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cstdio> #include <string> #include <queue> #include <cmath> #include <ctime> #include <map> #define lc root<<1 #define rc root<<1|1 #define reg(i,x) for(int i=first[x];i;i=nxt[i]) using namespace std; typedef long long LL; const int MAXN = 200011; const int MAXM = 400011; int n,m,q,ecnt,first[MAXN],nxt[MAXM],to[MAXM],size[MAXN],bel[MAXN],cnt,f[MAXN][2],D[MAXN]; double ans; map<int,double>mp[MAXN]; vector<int>w[MAXN]; vector<int>w2[MAXN]; inline void link(int x,int y){ nxt[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; } inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline void dfs(int x,int fa,int id){ bel[x]=id; size[id]++; reg(i,x) { int v=to[i]; if(v==fa) continue; dfs(v,x,id); if(f[v][0]+1>f[x][0]) f[x][1]=f[x][0],f[x][0]=f[v][0]+1; else if(f[v][0]+1>f[x][1]) f[x][1]=f[v][0]+1; } D[id]=max(D[id],f[x][0]+f[x][1]); } inline void dfs2(int x,int fa,int maxl){ int tmp=max(maxl,f[x][0]); w[ bel[x] ].push_back(tmp); w2[ bel[x] ].push_back(0); reg(i,x) { int v=to[i]; if(v==fa) continue; if(f[v][0]+1==f[x][0]) dfs2(v,x,max(maxl,f[x][1])+1); else dfs2(v,x,max(maxl,f[x][0])+1); } } inline int getp(int x,int val){ int l=0,r=w[x].size()-1,mid,pos; if(val>w[x][r]) return r; if(val<w[x][0]) return 0; while(l<=r) { mid=(l+r)>>1; if(w[x][mid]<=val) pos=mid,l=mid+1; else r=mid-1; } return pos+1; } inline void work(){ n=getint(); m=getint(); q=getint(); int x,y,r1,r2; for(int i=1;i<=m;i++) { x=getint(); y=getint(); link(x,y); link(y,x); } for(int i=1;i<=n;i++) if(!bel[i]) { dfs(i,0,++cnt); dfs2(i,0,0); } for(int i=1;i<=cnt;i++) sort(w[i].begin(),w[i].end()); for(int i=1;i<=cnt;i++) { w2[i][ w2[i].size()-1 ]=w[i][ w[i].size()-1 ]; //printf("---%d\n",w2[i][ w[i].size()-1 ]); for(int j=w2[i].size()-2;j>=0;j--) { w2[i][j]=w2[i][j+1]+w[i][j]; //printf("---%d\n",w2[i][j]); } } while(q--) { x=getint(); y=getint(); r1=bel[x]; r2=bel[y]; if(size[r1]>size[r2]) swap(r1,r2),swap(x,y); if(mp[r1][r2]!=0) ans=mp[r1][r2]; else { if(r1==r2) { puts("-1"); continue; } int lim=max(D[r1],D[r2]),pos; ans=0; for(int i=0,ss=w[r1].size();i<ss;i++) { pos=getp(r2,lim-1-w[r1][i]); ans+=(double)pos*lim; if(pos<w[r2].size()) ans+=w2[r2][pos]+(w[r1][i]+1)*(w[r2].size()-pos); } ans/=size[r1]; ans/=size[r2]; mp[r1][r2]=ans; } printf("%.8lf\n",ans); } } int main() { #ifndef ONLINE_JUDGE freopen("804.in","r",stdin); freopen("804.out","w",stdout); #endif work(); return 0; }
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!