zoukankan      html  css  js  c++  java
  • 「UVALive 4487」Exclusive OR 「带权并查集」「模拟」

    正经写了一个带权并查集的简单题。

    这个题的操作一共有两种:第一种是告诉你(X_p ext{xor} X_q = v),要判断与之前的信息是否矛盾。第二种是让你求一系列(X)的xor和,同时也要判断不知道的情况。

    不要问我为什么题目中是三个操作,因为第一个操作就是第二个操作。

    首先你需要读入,这个可以用sscanf。然后就可以开始带权并查集搞了。

    首先并查集里维护(xor_{u}),代表(X_u ext{xor} X_{f_u})的值。这个东西一开始都不知道,所以都设成0.

    当进行路径压缩的时候这么写:

    int find(int x) {
    	if (x == f[x]) return x;
    	int get = find(f[x]);
    	xor_[x] ^= xor_[f[x]];
    	return f[x] = get; 
    }
    

    这个东西成立是因为((a xor b) xor (b xor c)=a xor c).

    然后如果他告诉你了一条关系,你先找到对应并查集的代表,然后合并一下,注意要特判下恒0的情况。

    这里合并要判断他俩在不在一个集合里,可以结合代码理解:

    bool merge(int p, int q, int v) {
    	int fp = find(p), fq = find(q);
    	if (fp == fq) {
    		if ((xor_[p] ^ xor_[q]) != v) return 0;
    		return 1; 
    	}
    	if (fp == n) swap(fp, fq);
    	f[fp] = fq;
    	xor_[fp] = (xor_[p] ^ xor_[q] ^ v);
    	return 1; 
    }
    

    求那个东西也挺有意思的。

    考虑把在一个森林里的所有东西一块计算。

    注意到我们能搞出来的xor和=x1 xor xf xor x2 xor xf xor...xor xp xor xf

    如果我们消不掉xf,除非xf=0,否则一定无解。

    否则直接消即可。不知道为啥uva一直过不了,但是hdu就能过...

    #include <bits/stdc++.h>
    
    #define test(...) fprintf(stderr, __VA_ARGS__)
    #define dbg(x) cerr << #x << " = " << x << '
    '
    
    using namespace std;
    
    typedef long long ll;
    typedef pair <int, int> pii;
    typedef vector <int> vi;
    typedef unsigned int ui;
    typedef vector <pair <int, int> > edges;
    
    const int N = 1000005;
    char s[N], from[N];
    int f[N], xor_[N], n, q; 
    // xor_[x]: x -> fa[x]这条边的xor值
    // 路径压缩的时候顺带维护 
    int find(int x) {
    	if (x == f[x]) return x;
    	int get = find(f[x]);
    	xor_[x] ^= xor_[f[x]];
    	return f[x] = get; 
    }
    int case_num;
    bool merge(int p, int q, int v) {
    	int fp = find(p), fq = find(q);
    	if (fp == fq) {
    		if ((xor_[p] ^ xor_[q]) != v) return 0;
    		return 1; 
    	}
    	if (fp == n) swap(fp, fq);
    	f[fp] = fq;
    	xor_[fp] = (xor_[p] ^ xor_[q] ^ v);
    	return 1; 
    }
    
    int ans(vi now) {
    	int k = now.size(), ans = 0;
    	vi ind(k);
    	for (int i = 0; i < k; ++i) {
    		if (ind[i]) continue;
    		
    		int fi = find(now[i]), cnt = 0;
    		for (int j = i; j < k; ++j) {
    			int fj = find(now[j]);
    			if (!ind[j] && fi == fj) {
    				cnt++;
    				ind[j] = 1;
    				ans ^= xor_[now[j]];
    			}
    		}
    		if ((cnt & 1) && fi != n) return -1;
    	}
    	return ans; 
    }
    void solve() {
    	printf("Case %d:
    ", ++case_num);
    	for (int i = 0; i <= 1000000; ++i)
    		f[i] = i, xor_[i] = 0; 
    	bool flag = 0;
    	int facts = 0; 
    	while (q--) {
    		char op[3];
    		scanf("%s", op);
    		if (op[0] == 'I') {
    			gets(from);
    			int space = 0, p, q, v; 
    			for (int i = 1; from[i] != ''; ++i) 
    				if (from[i] == ' ') ++space;
    	//		dbg(space);
    			if (space == 1) {
    				sscanf(from, "%d%d", &p, &v);
    				q = n;
    			} else if (space == 2) 
    				sscanf(from, "%d%d%d", &p, &q, &v);
    			++facts; 
    			if (flag) continue;
    			if (!merge(p, q, v)) {
    				printf("The first %d facts are conflicting.
    ", facts);
    				flag = 1;
    			}
    		} else if (op[0] == 'Q') {
    			int k;
    			scanf ("%d", &k);
    			vi q(k);
    			for (int i = 0; i < k; ++i) scanf ("%d", &q[i]);
    			
    			if (flag) continue;
    			int result = ans(q);
    			if (result == -1) {
    				puts("I don't know.");
    			}
    			else printf("%d
    ", result);
    		}
    	}
    	puts("");
    }
    
    int main() {
    #ifdef LOCAL
    	freopen("sample.in", "r", stdin);
    #endif
      while (~scanf("%d%d", &n, &q) && (n || q)) solve();
      return 0;
    }
    
  • 相关阅读:
    JavaScript 高级
    JavaScript 归纳
    完全二叉树, 最大堆 , 堆排序
    二叉树
    Java秒杀系统方案优化 高性能高并发实战(1)
    精选 SQL 脚本
    树形结构有关的SQL
    在Sql server数据库中,关于触发器的创建、调用及删除
    SQLServer 唯一键约束和唯一索引有什么区别?
    很不错的 VBA 网址
  • 原文地址:https://www.cnblogs.com/LiM-817/p/12328836.html
Copyright © 2011-2022 走看看