CF891C Envy
题面
题解
首先要知道两个性质:
- 对于任意权值,最小生成树上该权值的边数是相同的。
- 对于任意一个最小生成树,当加完所有权值小于一个任意值的边之后,当前图的连通性是一样的。
于是我们按照权值分开处理,对每一种边的权值的每一个询问都处理一遍即可,这个可以写一个到撤销操作的并查集。
于是这道题目就做完了。
代码
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<vector>
#define RG register
#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)
#define clear(x, y) memset(x, y, sizeof(x))
inline int read()
{
int data = 0, w = 1; char ch = getchar();
while(ch != '-' && (!isdigit(ch))) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(isdigit(ch)) data = data * 10 + (ch ^ 48), ch = getchar();
return data * w;
}
const int maxn(5e5 + 10);
struct edge { int x, y, w; } e[maxn];
struct qry { int id, x, y, w; };
inline int cmp(const edge &lhs, const edge &rhs) { return lhs.w < rhs.w; }
std::vector<qry> Q[maxn];
int fa[maxn], size[maxn], ans[maxn], n, m, q, stk[maxn], top;
int find(int x) { return fa[x] == x ? x : find(fa[x]); }
inline int merge(int x, int y)
{
x = find(x), y = find(y);
if(x == y) return 0;
if(size[x] > size[y]) std::swap(x, y);
fa[x] = y, size[y] += size[x], stk[++top] = x;
return 1;
}
int main()
{
n = read(), m = read();
for(RG int i = 1; i <= m; i++)
e[i] = (edge) {read(), read(), read()};
q = read();
for(RG int i = 1, k; i <= q; i++)
{
k = read();
for(RG int j = 1, x; j <= k; j++)
x = read(), Q[e[x].w].push_back((qry) {i, e[x].x, e[x].y, e[x].w});
}
std::sort(e + 1, e + m + 1, cmp);
for(RG int i = 1; i <= n; i++) size[fa[i] = i] = 1;
for(RG int i = 1; i <= q; i++) ans[i] = 1;
for(RG int i = 1; i <= m; i++)
{
int val = e[i].w; top = 0;
for(RG int j = 0; j < (int)Q[val].size(); j++)
{
if(!ans[Q[val][j].id]) continue;
if(j > 0 && Q[val][j].id != Q[val][j - 1].id)
while(top)
{
int x = stk[top--];
size[fa[x]] -= size[x];
fa[x] = x;
}
if(!merge(Q[val][j].x, Q[val][j].y))
ans[Q[val][j].id] = 0;
}
while(e[i].w == val) merge(e[i].x, e[i].y), ++i;
if(e[i].w != val) --i;
}
for(RG int i = 1; i <= q; i++) puts(ans[i] ? "YES" : "NO");
return 0;
}