[题解] [CF891C] Envy

题面

题解

对于同一个图中的最小生成树, 有如下性质

  1. 对于不同最小生成树中同一权值的边的数量是一定的, 可通过反证法证明, 在这里就不证了
  2. 对于任意正确加边方案, 加完小于某权值的边后连通性是一样的

所以根据以上性质, 可以判断某一权值能否在一棵最小生成树中同时出现, 具体方法如下

在Kruscal的过程中, 当把小于某一权值的所有边都处理完后, 对于这一权值的所有边, 记录下每条边两个端点所在的联通块

然后对于每组询问, 将边的权值排序后对于每一种权值单独考虑(每一种权值互不影响, 自己思考一下为什么), 看这些边形成的联通块中是否有环, 并查集判断即可, 至于撤销并查集, 暴力撤销即可

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#define itn int
#define reaD read
#define N 500005
using namespace std;

int n, m, fa[N]; 
struct edge { int from, to, cost, ancf, anct, id; } e[N]; 
struct Edge { int u, v, w; bool operator < (const Edge &p) const { return w < p.w; } }; 
vector <Edge> vec; 

inline int read()
{
	int x = 0, w = 1; char c = getchar();
	while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
	return x * w;
}

bool cmp1(edge x, edge y) { return x.cost < y.cost; }

bool cmp2(edge x, edge y) { return x.id < y.id; }

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

void merge(int u, int v) { u = find(u), v = find(v); fa[u] = v; }

int main()
{
	n = read(); m = read(); 
	for(int i = 1; i <= n; i++) fa[i] = i; 
	for(int i = 1; i <= m; i++) e[i].from = read(), e[i].to = read(), e[i].cost = read(), e[i].id = i; 
	sort(e + 1, e + m + 1, cmp1); 
	for(int i = 1; i <= m; )
	{
		int pos = i;
		do
		{
			e[pos].ancf = find(e[pos].from);
			e[pos].anct = find(e[pos].to); 
			pos++; 
		}
		while(pos <= m && e[pos].cost == e[pos - 1].cost);
		while(i < pos)
		{
			if(find(e[i].from) == find(e[i].to)) i++;
			else merge(e[i].from, e[i].to), i++; 
		}
	}
	for(int i = 1; i <= n; i++) fa[i] = i; 
	sort(e + 1, e + m + 1, cmp2); 
	int Q = read();
	while(Q--)
	{
		int k = read(); vec.clear(); 
		for(int i = 1; i <= k; i++)
		{
			int id = read(); 
			vec.push_back((Edge) { e[id].ancf, e[id].anct, e[id].cost }); 
		}
		sort(vec.begin(), vec.end());
		bool flag = 1; 
		for(int i = 0; i < vec.size(); )
		{
			if(!flag) break; 
			if(vec[i].u == vec[i].v) { flag = 0; break; };
			merge(vec[i].u, vec[i].v); 
			int pos = i + 1;
			while(pos < vec.size() && vec[pos].w == vec[i].w)
			{
				if(find(vec[pos].u) == find(vec[pos].v)) { flag = 0; break; }
				merge(vec[pos].u, vec[pos].v); pos++; 
			}
			while(i < pos) { fa[vec[i].u] = vec[i].u; fa[vec[i].v] = vec[i].v; i++; }
		}
		puts(flag ? "YES" : "NO"); 
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/ztlztl/p/11182076.html