洛谷P4185 [USACO18JAN] MooTube G(带权并查集)

题目链接

https://www.luogu.com.cn/problem/P4185

思路

v i v_{i} vi个视频推荐列表中将推荐的视频数实际上就是缩点之后该点所在联通块的点的数量。

因此,我们考虑使用并查集。

我们可以采用离线做法。先将每一对关系按照相关性 r i r_{i} ri按照从大到小排序,之后将所有的询问按照 k i k_{i} ki的值从大到小排序。

这样,我们先将 k i k_{i} ki的值大的使用并查集进行缩点,并记录答案。这样从大到小的处理,不会影响后面答案的计算。

时间复杂度: O ( n l o g 2 n ) O(nlog_{2}n) O(nlog2n)

代码

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5;
int n, q;
struct Edge
{
	int a, b, r;
	bool operator<(const Edge & x) {
		return r > x.r;
	}
};
vector<Edge>edge;
struct node
{
	int k, v, id, ans;
} p[N];
struct DSU {
	std::vector<int> f, siz;

	DSU() {}
	DSU(int n) {
		init(n);
	}

	void init(int n) {
		f.resize(n);
		std::iota(f.begin(), f.end(), 0);
		siz.assign(n, 1);
	}

	int find(int x) {
		while (x != f[x]) {
			x = f[x] = f[f[x]];
		}
		return x;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	bool merge(int x, int y) {
		x = find(x);
		y = find(y);
		if (x == y) {
			return false;
		}
		siz[x] += siz[y];
		f[y] = x;
		return true;
	}

	int size(int x) {
		return siz[find(x)];
	}
};
void solve()
{
	cin >> n >> q;
	DSU dsu(n + 1);
	for (int i = 1, a, b, r; i < n; i++)
	{
		cin >> a >> b >> r;
		edge.push_back({a, b, r});
	}
	sort(edge.begin(), edge.end());
	for (int i = 1; i <= q; i++)
	{
		cin >> p[i].k >> p[i].v;
		p[i].id = i;
		p[i].ans = 0;
	}
	sort(p + 1, p + 1 + q, [&](node x, node y) {return x.k > y.k;});
	int idx = 0;
	for (int i = 1; i <= q; i++)
	{
		while (idx < edge.size() && edge[idx].r >= p[i].k)
		{
			dsu.merge(edge[idx].a, edge[idx].b);
			idx++;
		}
		p[i].ans = dsu.siz[dsu.find(p[i].v)] - 1;
	}
	sort(p + 1, p + 1 + q, [&](node x, node y) {return x.id < y.id;});
	for (int i = 1; i <= q; i++)
	{
		cout << p[i].ans << endl;
	}
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	int test = 1;
	// cin >> test;
	for (int i = 1; i <= test; i++)
	{
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值