「CF891C」Envy

Posted zsbzsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「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)

以上是关于「CF891C」Envy的主要内容,如果未能解决你的问题,请参考以下文章

「CF891C」Envy

[题解] [CF891C] Envy

[CF891C] Envy - Kruskal,并查集

CF 891C Envy 最小生成树+可撤销并查集

CodeForces - 891C: Envy(可撤销的并查集&最小生成树)

惠普 ENVY 16 创意本 评测