Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)

题目链接 Expected diameter of a tree

题目意思就是给出一片森林,

若把任意两棵树合并(合并方法为在两个树上各自任选一点然后连一条新的边)

求这棵新的树的树的直径的期望长度。

 

我们对每棵独立的树,对于这棵树的每一个点$u$,求出$f[u]$

$f[u]$为这棵树上离$u$最远的点到$u$的距离。

同时我们求出每棵树上的树的直径的长度

 

现在合并两棵树$A$和$B$的时候,合成的新的树的直径$C$其实有三种情况。

对$A$树中的某点$x$,$B$树中的某点$y$

1、可能是$A$树中树的直径,长度为$d[A]$

2、可能是$B$树中树的直径,长度为$d[B]$

3、可能是:离$A$树中点$x$最远的点$-->x-->y-->$离$B$树中点$y$最远的点

     长度为$f[x] + f[y] + 1$

 

三种情求最大值即可

在枚举所有情况的时候,对每个点x枚举y

我们要求的是$max(f[x] + f[y] + 1, d[A], d[B])$

其中令$max(d[A], d[B]) = Z$

那么我们要求的就是$max(f[x] + f[y] + 1, Z)$

我们两两枚举$x$和$y$显然是要超时的,怎么优化呢?

我们可以在两棵树中选一棵规模较小的树,枚举这棵树上的每个点$x$

对于另一棵树$B$,二分一个临界值,在这个临界值两边

我分别取较大的$f[x] + f[y] + 1$ 或是 $Z$

 

这道题数据规模比较大,询问的时候的给出两个点,一个点在$A$树上,一个点在$B$树上

所以他如果不友好一点,在某两棵点很多的树上选很多不同的点对来构成很多次询问。

但事实上他们的本质是同一个询问,这个时候还是有可能超时。

那么我们就把每棵独立的树编号,每次处理完一个询问,把答案塞到map里面

那么下一次处理到本质相同的询问的时候,就可以直接拿出来了。

 

(这道题真的很锻炼代码能力,当初做的时候调了好几个小时……)

 

  1 #include <bits/stdc++.h>
  2 
  3 using namespace std;
  4 
  5 #define rep(i, a, b)    for (int i(a); i <= (b); ++i)
  6 #define dec(i, a, b)    for (int i(a); i >= (b); --i)
  7 
  8 typedef long long LL;
  9 
 10 const int N = 100010;
 11 
 12 int n, m, q, L, R, nowdep, treenum = 0;
 13 int father[N], tr[N], c[N], f[N], d_max[N];
 14 vector <int> v[N], tree[N], dis[N], g[N];
 15 
 16 set < int > st;
 17 map < int, int  > mp;
 18 map < pair<int, int> , double > ans;
 19 map < pair<int, int> , int    > flag;
 20 
 21 int getfather(int x){
 22     return father[x] ? father[x] = getfather(father[x]) : x;
 23 }
 24 
 25 void dfs(int x, int fa, int dep){
 26     f[x] = max(f[x], dep);
 27     for (auto u : v[x]){
 28         if (u == fa) continue;
 29         dfs(u, x, dep + 1);
 30     }
 31 }    
 32 
 33 void dfs1(int x, int fa, int dep){
 34     if (dep > nowdep){
 35         L = x;
 36         nowdep = dep;
 37     }
 38 
 39     for (auto u : v[x]){
 40         if (u == fa) continue;
 41         dfs1(u, x, dep + 1);
 42     }
 43 }
 44 
 45 void dfs2(int x, int fa, int dep){
 46     if (dep > nowdep){
 47         R = x;
 48         nowdep = dep;
 49     }
 50 
 51     for (auto u : v[x]){
 52         if (u == fa) continue;
 53         dfs2(u, x, dep + 1);
 54     }
 55 }
 56 
 57 int main(){
 58 
 59     scanf("%d%d%d", &n, &m, &q);
 60     memset(father, 0, sizeof father);
 61     rep(i, 1, m){
 62         int x, y;
 63         scanf("%d%d", &x, &y);
 64         v[x].push_back(y);
 65         v[y].push_back(x);
 66         int fa = getfather(x), fb = getfather(y);
 67         if (fa != fb) father[fa] = fb;
 68     }
 69 
 70     rep(i, 1, n) st.insert(getfather(i));
 71     
 72     for (auto u : st){
 73         mp[u] = ++treenum;
 74         tr[treenum] = u;
 75     }
 76 
 77     rep(i, 1, n){
 78         int x = getfather(i);
 79         tree[mp[x]].push_back(i);
 80         c[i] = mp[x];
 81     }
 82 
 83     memset(f, 0, sizeof f);
 84 
 85     rep(i, 1, treenum){
 86         L = 0; nowdep = -1;
 87         dfs1(tree[i][0], 0, 0);
 88         R = 0, nowdep = -1;
 89         dfs2(L, 0, 0);
 90         dfs(L, 0, 0);
 91         dfs(R, 0, 0);
 92         for (auto u : tree[i]) dis[i].push_back(f[u]);
 93         sort(dis[i].begin(), dis[i].end());
 94         rep(j, 0, (int)tree[i].size() - 1){
 95             if (j == 0) g[i].push_back(dis[i][j]);
 96             else g[i].push_back(g[i][j - 1] + dis[i][j]);
 97         }
 98         d_max[i] = dis[i][(int)tree[i].size() - 1];
 99     }
100 
101     ans.clear();
102     flag.clear();
103 
104     for (; q--; ){
105         int x, y;
106         scanf("%d%d", &x, &y);
107         if (c[x] == c[y]){
108             puts("-1");
109             continue;
110         }
111         int na = c[x], nb = c[y];
112         if ((int) tree[na].size() > (int) tree[nb].size()) swap(na, nb);
113         if (flag[{na, nb}]){
114             printf("%.12f\n", ans[{na, nb}]);
115             continue;
116         }
117         
118         LL X = 0;
119         LL Y = (LL) tree[na].size() * tree[nb].size();
120         LL Z = max(d_max[na], d_max[nb]);
121         for (auto u1 : tree[na]){
122             LL A = lower_bound(dis[nb].begin(), dis[nb].end(), Z - 1 - f[u1]) - dis[nb].begin();
123             X += (LL) A * Z + 
124                              (LL) (g[nb][(int)tree[nb].size() - 1] +  (int)tree[nb].size() - A - (A ? g[nb][A - 1] : 0)) + 
125                              (f[u1]) * ((LL) tree[nb].size() - A);
126         }
127         
128                 double cnt_ans = (double) X / (double) Y;
129         printf("%.12f\n", cnt_ans);
130         
131         flag[{na, nb}] = 1;
132         ans[{na, nb}] = cnt_ans;
133     }
134 
135     return 0;
136 }

 

posted @ 2017-07-04 12:45  cxhscst2  阅读(219)  评论(0编辑  收藏  举报