• [2013 ACM/ICPC Asia Regional Nanjing Online C][hdu 4750]Count The Pairs(kruskal + 二分)


    http://acm.hdu.edu.cn/showproblem.php?pid=4750

     

    题意:

    定义f(u,v)为u到v每条路径上的最大边的最小值..现在有一些询问..问f(u,v)>=t的点对有所少对,注意(1,2)和(2,1)是不同的点对


    分析:

    原来最小生成树有一个很鬼畜的结论,那就是一个图的最小生成树中任意两个点的路径中的最大边一定最小。(妈蛋,完全不知道这个)

    然后此题就变得很明朗了,用kruskal算法,加边的时候此边连接的两个集合的路径中的最大边就是这个边,存储下来,询问的时候二分查找即可。

     1 #pragma comment(linker, "/STACK:102400000,102400000")
     2 #include <cstdio>
     3 #include <algorithm>
     4 #include <cstring>
     5 typedef long long ll;
     6 struct Edge {
     7     int u, v, len;
     8 };
     9 const int N = 10000 + 3;
    10 const int E = 500000 + 3;
    11 
    12 int fa[N], cnt[N];
    13 
    14 Edge eg[E];
    15 int idx, id[E];
    16 
    17 int n, m;
    18 ll ans[E];
    19 
    20 int Find(int x) {
    21     if (fa[x] != x) fa[x] = Find(fa[x]);
    22     return fa[x];
    23 }
    24 bool cmp(const Edge& a, const Edge& b) {
    25     return a.len < b.len;
    26 }
    27 void work() {
    28     for (int i = 1; i <= n; ++i)
    29         fa[i] = i, cnt[i] = 1;
    30 
    31     id[0] = -1;
    32     for (int i = 0; i < m; ++i) {
    33         scanf("%d%d%d", &eg[i].u, &eg[i].v, &eg[i].len);
    34         ++eg[i].u, ++eg[i].v;
    35         id[i + 1] = eg[i].len;
    36     }
    37 
    38     std::sort(id, id + m + 1);
    39     for (int i = 0; i < m; ++i)
    40         eg[i].len = std::lower_bound(id, id + m + 1, eg[i].len) - id;
    41 
    42     memset(ans, 0sizeof(ans));
    43 
    44     std::sort(eg, eg + m, cmp);
    45     int x, y;
    46     for (int i = 0; i < m; ++i) {
    47         x = Find(eg[i].u), y = Find(eg[i].v);
    48         if (x != y) {
    49             ans[eg[i].len] = ans[eg[i].len] + cnt[x] * cnt[y];
    50             cnt[x] += cnt[y];
    51             fa[y] = x;
    52         }
    53     }
    54 
    55     for (int i = m; i >= 0; --i)
    56         ans[i] = ans[i] + ans[i + 1];
    57 
    58     int Q, l, r, mid;
    59     scanf("%d", &Q);
    60     while (Q -- > 0) {
    61         scanf("%d", &x);
    62         l = -1, r = m + 1;
    63         while (r - l > 1) {
    64             mid = (l + r) >> 1;
    65             if (id[mid] >= x)
    66                 r = mid;
    67             else
    68                 l = mid;
    69         }
    70         printf("%lld ", ans[r] * 2);
    71     }
    72 }
    73 int main() {
    74 //    freopen("a.in", "r", stdin);
    75     while (2 == scanf("%d%d", &n, &m)) {
    76         work();
    77     }
    78     return 0;
    79 }
    View Code 
  • 相关阅读:
    C++ handle(句柄类) part2
    C++代理类的使用
    第一个blog
    C++ Handle(句柄) part1
    关于理想团队的构建和对软件流程的理解
    提供就医帮助的安卓APP
    上海地铁游移动APP需求分析
    关于学习了《构建之法》的若干存在疑惑的问题
    安卓APP开发简单实例 结对编程心得
    Vue修改Vue项目运行端口号(CLI2)
  • 原文地址:https://www.cnblogs.com/hewifi/p/3337575.html
Copyright © 2020-2023  润新知