[题解] [CF891C] Envy
题面
题解
对于同一个图中的最小生成树, 有如下性质
- 对于不同最小生成树中同一权值的边的数量是一定的, 可通过反证法证明, 在这里就不证了
- 对于任意正确加边方案, 加完小于某权值的边后连通性是一样的
所以根据以上性质, 可以判断某一权值能否在一棵最小生成树中同时出现, 具体方法如下
在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;
}