HDU-5441 Travel(并查集)

题意:

给一个无向图,n个点m条边,每条边都有一个权值,然后q次询问,每次给出一个数值,求用到所有边权不大于这个数值的边的情况下,能够互相到达的点对的个数。

思路:

因为如果点对符合询问中数值较小的,那么肯定要符合数值较大的,所以对所有边按权值小到大排序,所有询问按数值小到大排序。所以根据不断遍历所有小于当前询问的所有边,然后看他们属于几个连通块中,计算点对数其实就是对于一个连通块中取出任意两个点,然后再对所有连通块进行加和。复杂度为O(m+q);

代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 1e5+5;
struct node
{
	int u, v, w;
	bool operator<(const node k)const
	{
		return w < k.w;
	}
} e[maxn], p[maxn];
int t, n, m, q;
int f[maxn];
int num[maxn];
ll ans[maxn];
int getF(int x)
{
	if(x == f[x]) return x;
	int y = x, tmp;
	while(f[x] != x) x = f[x];
	while(y != f[y])
	{
		tmp = f[y];
		f[y] = x;
		y = tmp;
	}
	return x;
}
int main()
{
	for(scanf("%d", &t); t--;)
	{
		scanf("%d %d %d", &n, &m, &q);
		for(int i = 1; i <= n; ++i)
		f[i] = i, num[i] = 1;
		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 < q; ++i)
		scanf("%d", &p[i].w), p[i].u = i;
		sort(e, e+m);
		sort(p, p+q);
		int k = 0; ll sum = 0;
		for(int i = 0; i < q; ++i)
		{
			while(k < m && e[k].w <= p[i].w)
			{
				int fa = getF(e[k].u), fb = getF(e[k].v);
				if(fa != fb)
				{
					f[fb] = fa;
					sum -= num[fa]*(num[fa]-1);
					sum -= num[fb]*(num[fb]-1);
					num[fa] += num[fb];
					sum += num[fa]*(num[fa]-1);
				}
				++k;
			}
			ans[p[i].u] = sum;
		}
		for(int i = 0; i < q; ++i)
		printf("%lld\n", ans[i]);
	}
	return 0;
}


继续加油~

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值