zoukankan      html  css  js  c++  java
  • Codeforces 1166F 并查集 启发式合并

    题意:给你一张无向图,无向图中每条边有颜色。有两种操作,一种是询问从x到y是否有双彩虹路,一种是在x到y之间添加一条颜色为z的边。双彩虹路是指:如果给这条路径的点编号,那么第i个点和第i - 1个点相连的边与第i个点和第i + 1个点相连的边颜色一样,其中i是偶数。

    思路:这个问题相当于初了最后一步没有限制以外(最后一步只走一条边),每一步都要走颜色相同的两条边。我们先不考虑最后一步的问题,只考虑每一步都要走颜色相同的两条边,那么我们只需要扫描每一个点的出边,如果有两条边颜色相同,就在一张新图上把这两条边除这个点以外的端点相连,这样询问就变成了判断两个点是否在一个连通块中。因为只是判断是否在同一连通块中,我们不需要建图,用并查集就可以了。现在需要考虑最后一步的问题,我们可以用一个set维护与这个节点直接相邻的点,这样对于询问x, y,如果y在连通块x的相邻节点中,也可以。对于加边的操作,相当于并查集的合并,但是同时需要合并的还有set, 我们合并的时候需要判断一下两个集合的大小,把小的插入大的里面,这样可以保证每次集合合并复杂度是O(logn * logn)的。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 100010;
    set<int> s[maxn];
    set<int>::iterator it1;
    set<pair<int, int> > edge[maxn];
    set<pair<int, int> >::iterator it;
    int f[maxn];
    int get(int x) {
    	if(x == f[x]) return x;
    	return f[x] = get(f[x]);
    }
    void merge(int x, int y) {
    	int x1 = get(x), y1 = get(y);
    	if(x1 == y1) return;
    	if(s[x1].size() < s[y1].size()) swap(x1, y1);
    	for (it1 = s[y1].begin(); it1 != s[y1].end(); it1++) {
    		s[x1].insert(*it1);
    	}
    	s[y1].clear();
    	f[y1] = x1;
    }
    void add(int x, int y, int z) {
    	s[get(x)].insert(y);
    	it = edge[x].lower_bound(make_pair(z, -1));
    	if(it == edge[x].end() || it -> first != z) {
    		edge[x].insert(make_pair(z, y));
    	} else {
    		merge(it -> second, y);
    	}
    }
    int main() {
    	int x, y, z, n, m, c, T;
    	char op[5];
    	scanf("%d%d%d%d", &n, &m, &c, &T);
    	for (int i = 1; i <= n; i++) f[i] = i;
    	for (int i = 1; i <= m; i++) {
    		scanf("%d%d%d", &x, &y, &z);
    		add(x, y, z);
    		add(y, x, z);
    	}
    	while(T--) {
    		scanf("%s", op + 1);
    		if(op[1] == '+') {
    			scanf("%d%d%d", &x, &y, &z);
    			add(x, y, z);
    			add(y, x, z);
    		} else {
    			scanf("%d%d", &x, &y);
    			if(get(x) == get(y)) {
    				printf("Yes
    ");
    			} else if(s[get(x)].find(y) != s[get(x)].end()) {
    				printf("Yes
    ");
    			} else {
    				printf("No
    ");
    			}
    		}
    	}
    } 
    

      

  • 相关阅读:
    hdu 5646 DZY Loves Partition
    bzoj 1001 狼抓兔子 平面图最小割
    poj 1815 Friendship 最小割 拆点 输出字典序
    spoj 1693 Coconuts 最小割 二者取其一式
    hdu 5643 King's Game 约瑟夫环变形
    约瑟夫环问题
    hdu 5642 King's Order
    CodeForces 631C Report
    1039: C语言程序设计教程(第三版)课后习题9.4
    1043: C语言程序设计教程(第三版)课后习题10.1
  • 原文地址:https://www.cnblogs.com/pkgunboat/p/10895050.html
Copyright © 2011-2022 走看看