码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 3938 Portal(并查集,离线)

时间:2020-05-29 23:01:22      阅读:59      评论:0      收藏:0      [点我收藏+]

标签:增加   https   ble   pre   for   lan   class   解题思路   ref   

题目链接

题目大意

??查询有多少对(x,y),使得x到y至少存在一条路径,路径上的边权值最大值不超过L。

解题思路

??从小到达依次枚举各个边,就能得到若干个图,图里的每条边都不大于当前的最大边(废话)。但是问题在于如何求出每次新加入一条边之后的点的对数,因为所有的边不一定是全都连接一起的。
??如果一条边把一个点连入一个图里的话,那么这个点与图里的每一个点都能形成一个新的点对,那么新增加的点对就是图中的点的个数。如果一条边把一个图与另外一个图相连呢?那么新增的点对就是两个图的点的个数之积。所以我们只要需要用一个并查集来维护所有点之间的关系和每个集合里的点的个数就行了。

代码

const int maxn = 1e4+10;
struct Q {
    int qs, num;
} q[maxn];
struct E {
    int u, v, w;
} e[5*maxn];
int n, m, qes, p[maxn], cnt[maxn], ans[maxn];
int find(int x) {
    return p[x] == x ? p[x] : p[x] = find(p[x]);
}
int main() {
    while(~scanf("%d%d%d",&n,&m,&qes)) {
        for (int i = 0; i<m; ++i) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
        for (int i = 0; i<qes; ++i) {
            scanf("%d", &q[i].qs);
            q[i].num = i; ans[i] = 0;
        }
        sort(e, e+m, [](E a, E b) {return a.w<b.w;});
        sort(q, q+qes, [](Q a, Q b) {return a.qs<b.qs;});
        for (int i = 1; i<=n; ++i) {
            p[i] = i; cnt[i] = 1;
        }
        int k = 0, sum = 0;
        for (int i = 0; i<m; ++i) {
            while(k<qes&&q[k].qs<e[i].w) ans[q[k++].num] = sum;
            int fa = find(e[i].u), fb = find(e[i].v);
            if (fa!=fb) {
                sum += cnt[fa]*cnt[fb];
                cnt[fb] += cnt[fa];
                p[fa] = fb;
            }
        }
        while(k<qes&&q[k].qs>=e[m-1].w) ans[q[k++].num] = sum;
        for (int i = 0; i<qes; ++i) printf("%d\n", ans[i]);
    }
    return 0;
}

HDU 3938 Portal(并查集,离线)

标签:增加   https   ble   pre   for   lan   class   解题思路   ref   

原文地址:https://www.cnblogs.com/shuitiangong/p/12989956.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!