zoukankan      html  css  js  c++  java
  • 「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)

  • 相关阅读:
    Abstract与Virtual
    List 常用方法
    控制数据采样分布 计算概念
    中期答辩感想
    软件开发之团队理解
    详细设计理解
    竞赛系统需求分析
    软件代码规范之理解
    AngularJS 整理资料
    AngularJS合集
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11745790.html
Copyright © 2011-2022 走看看