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 }