Codeforces 804D

来源:互联网 发布:mac 微软雅黑字体关了 编辑:程序博客网 时间:2024/05/29 14:41

首先对于每棵树求出从每个点出发最长路径的长度(他们中最大值为直径)
从小到大排序,并记录前缀和。一开始我以为处理询问时有厉害的做法,但事实上就是利用启发式的思想,挑选点较小的那一棵树,然后枚举所有的点,由于答案是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 doubleusing 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;}
0 0
原创粉丝点击