您的位置:首页 > 其它

离线+带权并查集 hdoj3938 Portal

2017-05-17 23:33 274 查看
题目传送门: http://acm.hdu.edu.cn/showproblem.php?pid=3938

题目的题意有些不清楚,看了discuss才明白。定义图上一条路径的cost为路径中所有边权中最大的那个。对于给定的图,回答当最大的路径长度为l的时候,最多可以有多少顶点对是可及的。

按照Kruskal的思路,按边权从小到大连接顶点,每次相连,如果减少一个连通分量,那么可及顶点对就会增大,增大的个数就是原来两个连通分量顶点个数的乘积,不断累加就可以得到对于不同的l,一共有多少顶点对。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int M = 5e4 + 5;
const int N = 1e4 + 5;
int father
, sum
, ans
;
int n, m, t;
struct edge {
int u, v, w;
} e[M];
struct query {
int id, l;
} q
;
bool cmp(const edge &e1, const edge &e2)
{
return e1.w < e2.w;
}
bool cmp1(const query &q1, const query &q2)
{
return q1.l < q2.l;
}
int find(int x)
{
while (x != father[x]) {
father[x] = father[father[x]];
x = father[x];
}
return x;
}
int merge(int x, int y)
{
x = find(x);
y = find(y);
if (x != y) {
father[y] = x;
sum[x] += sum[y];
return (sum[x] - sum[y]) * sum[y];
} else return 0;
}
void init(void)
{
for (int i = 1; i <= n; i ++) {
sum[i] = 1;
father[i] = i;
}
}
int main()
{
while (~scanf("%d%d%d", &n, &m, &t)) {
init();
for (int i = 1; i <= m; i ++) {
scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
}
sort(e + 1, e + 1 + m, cmp);
for (int i = 1; i <= t; i ++) {
scanf("%d",&q[i].l);
q[i].id = i;
}
sort(q + 1, q + 1 + t, cmp1);
int cnt = 0, j = 1;
for (int i = 1; i <= t; i ++) {
while (j <= m && e[j].w <= q[i].l) {
cnt += merge(e[j].u, e[j].v);
++ j;
}
ans[q[i].id] = cnt;
}
for (int i = 1; i <= t; i ++) {
printf("%d\n", ans[i]);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  并查集