zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", cnt_ans);
    130         
    131         flag[{na, nb}] = 1;
    132         ans[{na, nb}] = cnt_ans;
    133     }
    134 
    135     return 0;
    136 }
  • 相关阅读:
    深入浅出MFC——MFC六大关键技术仿真(二)
    错误:Invalid action class configuration that references an unknown class named [XXX]的解决
    错误:java.lang.NoClassDefFoundError: com/project/common/exception/ServiceException 的解决
    SQL查询语句优化的实用方法
    ueditor表格边框没有颜色的解决
    ueditor显示内容末尾有多余标记的解决
    form表单中enctype属性作用
    springMVC中@RequestParam和@RequestBody注解的用法
    错误:This function has none of DETERMINISTIC... 的解决
    如何区分内存类型及查看内存的兼容性
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7116053.html
Copyright © 2011-2022 走看看