「CF891C」Envy

传送门
Luogu

解题思路

考虑最小生成树的几个性质:

  • 所有最小生成树中边权相等的边的条数相等
  • 在任意一颗最小生成树中,边权相等的边所联通的点集一定

那么我们考虑把边权相等的边单独拿出来考虑。
每次把并查集恢复到加边前的状态,然后再判断这些边加进去会不会形成环即可。

PS. 恢复并查集时,可以考虑求出每一条边在 ( ext{Kruskal}) 的过程中,将要被加入时两端点所在联通块。

细节注意事项

  • 有点难实现,要有耐心

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
	s = 0; int f = 0; char c = getchar();
	while (!isdigit(c)) f |= (c == '-'), c = getchar();
	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
	s = f ? -s : s;
}

const int _ = 500010;

int fa[_], siz[_];

inline void init(int n) { for (rg int i = 1; i <= n; ++i) fa[i] = i; }

inline int findd(int x) { return fa[x] == x ? x : fa[x] = findd(fa[x]); }

inline void merge(int x, int y) { fa[findd(x)] = findd(y); }

int n, m, q;
struct edge{ int x, y, val, id, tx, ty; }g[_], e[_];

inline bool cmp(const edge& x, const edge& y) { return x.val < y.val; }

inline bool Cmp(const edge& x, const edge& y) { return x.id < y.id; }

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.in", "r", stdin);
#endif
	read(n), read(m);
	for (rg int i = 1; i <= m; ++i)
		read(g[i].x), read(g[i].y), read(g[i].val), g[i].id = i;
	init(n), sort(g + 1, g + m + 1, cmp);
	for (rg int i = 1; i <= m; ) {
		int j = i;
		do {
			g[j].tx = findd(g[j].x);
			g[j].ty = findd(g[j].y);
			++j;
		} while (j <= m && g[j].val == g[i].val);
		while (i < j) {
			while (findd(g[i].x) == findd(g[i].y) && i < j) ++i;
			if (i < j) merge(g[i].x, g[i].y);
		}
	}
	init(n), sort(g + 1, g + m + 1, Cmp);
	for (read(q); q--; ) {
		int s; read(s);
		for (rg int x, i = 1; i <= s; ++i)
			read(x), e[i] = (edge) { g[x].tx, g[x].ty, g[x].val };
		sort(e + 1, e + s + 1, cmp);
		int flag = 1;
		for (rg int i = 1; i <= s && flag; ) {
			int j = i;
			do {
				if (findd(e[j].x) == findd(e[j].y)) { flag = 0; break; }
				merge(e[j].x, e[j].y), ++j;
			} while (j <= s && e[j].val == e[i].val);
			while (i < j) fa[e[i].x] = e[i].x, fa[e[i].y] = e[i].y, ++i;
		}
		puts(flag ? "YES" : "NO");
	}
	return 0;
}

完结撒花 (qwq)

原文地址:https://www.cnblogs.com/zsbzsb/p/11745790.html