旅游【并查集】

这篇博客介绍了一种利用并查集解决旅游线路人气统计的问题。内容包括问题描述、输入输出格式、样例输入输出,以及解题思路。博主通过排序边和查询值,当边的人气值小于等于查询值时,使用并查集合并相关节点,并记录每个集合的总人数,最后计算答案。给出的解题方案中,重点在于并查集的实现和集合总数的计算。
摘要由CSDN通过智能技术生成

>Description
在这里插入图片描述


>Input
在这里插入图片描述

>Output
在这里插入图片描述
在这里插入图片描述


>Sample Input
1
5 5 3
2 3 6334
1 5 15724
3 5 5705
4 3 12382
1 3 21726
6000
10000
13000

>Sample Output
2
6
12


>解题思路
并查集实现。

把边和询问的x都排个序,如果边的人气值小于等于x的话就把边连接的两点(x,y)进行合并,同时顺便记录一下 s [ i ] s[i] s[i]每个集合的总数,ans累加上 s [ x ] ∗ s [ y ] ∗ 2 s[x]*s[y]*2 s[x]s[y]2


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define int long long
using namespace std;

struct line
{
	int x, y, c;
} a[100005];
struct ask
{
	int h, c, ans;
} w[5005];
int T, n, m, q, c[20005], s[20005];

int read ()
{
	int l = 0;
	char cc = getchar();
	while (cc > '9' || cc < '0') cc = getchar();
	while (cc >= '0' && cc <= '9')
	{
		l = l * 10 + cc - '0';
		cc = getchar();
	}
	return l;
}
bool bmp (line aa, line bb) {return aa.c < bb.c;}
bool bmp2 (ask aa, ask bb) {return aa.c < bb.c;}
bool bmp3 (ask aa, ask bb) {return aa.h < bb.h;}
int find (int now)
{
	if (c[now] == now) return now;
	s[c[now]] += s[now];
	s[now] = 0; //处理集合大小
	return c[now] = find (c[now]);
}
void work ()
{
	n = read (), m = read (), q = read ();
	for (int i = 1; i <= n; i++)
	  c[i] = i, s[i] = 1; //清空
	for (int i = 1; i <= m; i++)
	  a[i].x = read (), a[i].y = read (), a[i].c = read ();
	sort (a + 1, a + 1 + m, bmp); //边排个序
	
	for (int i = 1; i <= q; i++)
	  w[i].c = read (), w[i].h = i;
	sort (w + 1, w + 1 + q, bmp2); //询问排个序
	int p = 1;
	w[0].ans = 0;
	for (int k = 1; k <= q; k++)
	{
		w[k].ans = w[k - 1].ans;
		for (int i = p; i <= m; i++) //p记录上一次询问到的边
		{
			if (a[i].c > w[k].c) {p = i; break;}
			int u = find (a[i].x), v = find (a[i].y);
			if (u != v)
			{
				c[u] = v;
				w[k].ans += s[v] * s[u] * 2;
				s[v] += s[u], s[u] = 0;
			}
		}
	}
	sort (w + 1, w + 1 + q, bmp3); //按输入顺序输出
	for (int i = 1; i <= q; i++)
	  printf ("%lld\n", w[i].ans);
}

signed main()
{
	T = read ();
	for (int i = 1; i <= T; i++)
	  work ();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值