您的位置:首页 > 其它

Codeforces 804D

2017-05-07 23:35 169 查看
首先对于每棵树求出从每个点出发最长路径的长度(他们中最大值为直径)

从小到大排序,并记录前缀和。一开始我以为处理询问时有厉害的做法,但事实上就是利用启发式的思想,挑选点较小的那一棵树,然后枚举所有的点,由于答案是max(f1+f2+1,max(d1,d2)),所以我们要在另一颗树中二分答案,找到大于max(d1,d2)的位置,再根据前缀和计算答案。每次处理询问时用map保存下结果,这样复杂度就得到了保证。

计算最长路径那个部分需要用到两次dfs,第一次直接记录它往下走的最长长度,第二次dfs相当于换根,把它调整为根计算答案,dfs完后还要调整回来,这也是换根的树形dp中常见的做法

include<bits/stdc++.h>
#define ll long long
#define ld double
using namespace std;
const int maxn=100000+10;
int rt[maxn],n,m,q,down[maxn],sz[maxn],d[maxn],zj[maxn],cnt;
vector<int> g[maxn];
vector<int> h[maxn];
vector<ll> sum[maxn];
map<int,ld> mp[maxn];
void dfs1(int p,int fa)
{
sz[rt[p]]++;
for(int i=0;i<g[p].size();i++)
{
int v=g[p][i];if(v==fa) continue;
rt[v]=rt[p];dfs1(v,p);
down[p]=max(down[p],down[v]+1);
}
}
void dfs2(int p,int fa)
{
int mx1=-1,mx2=-1;d[p]=down[p];
for(int i=0;i<g[p].size();i++)
{
int v=g[p][i];
if(down[v]>mx1)
{
mx2=mx1;
mx1=down[v];
}
else if(down[v]>mx2) mx2=down[v];
}

for(int i=0;i<g[p].size();i++)
{
int v=g[p][i],val=down[p],v2=down[v];if(v==fa) continue;
if(down[v]==mx1) down[p]=mx2+1;
else down[p]=mx1+1;
down[v]=max(down[v],down[p]+1);
dfs2(v,p);
down[p]=val;
down[v]=v2;
}
}
int main()
{
//freopen("test.in","r",stdin);
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
for(int i=1;i<=n;i++)
if(!rt[i])
{
rt[i]=++cnt;
dfs1(i,0);
dfs2(i,0);
}
for(int i=1;i<=n;i++)
{
zj[rt[i]]=max(zj[rt[i]],d[i]);
h[rt[i]].push_back(d[i]);
}
for(int i=1;i<=cnt;i++)
{
sort(h[i].begin(),h[i].end());
sum[i].push_back(h[i][0]);
for(int j=1;j<h[i].size();j++)
sum[i].push_back(sum[i][j-1]+h[i][j]);
}
for(int i=1;i<=q;i++)
{
int x,y,u,v;scanf("%d%d",&x,&y);
u=rt[x];v=rt[y];
if(u==v) puts("-1");
else
{
if(sz[u]>sz[v]||(sz[u]==sz[v]&&u>v)) swap(u,v);
if(mp[u].count(v)) printf("%.9lf\n",mp[u][v]);
else
{
int maxx=max(zj[u],zj[v]);ll res=0;
for(int j=0;j<h[u].size();j++)
{
int p=h[u][j];
if(h[v][sz[v]-1]+p+1<=maxx) res+=(ll)sz[v]*maxx;
else
{
int nx=upper_bound(h[v].begin(),h[v].end(),maxx-1-p)-h[v].begin();
res+=(ll)nx*maxx+(ll)(sz[v]-nx)*(p+1);
res+=sum[v][sz[v]-1];
if(nx) res-=sum[v][nx-1];
}
}
ld out=(ld)res/((ld)sz[u]*sz[v]);
printf("%.9lf\n",out);
mp[u][v]=out;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息