UVA - 12232 Exclusive-OR (并查集扩展偏离向量)

Description

Download as PDF

You are not given n non-negative integersX0,X1,..., Xn-1 less than220, but they do exist, and their values never change.

I'll gradually provide you some facts about them, and ask you some questions.

There are two kinds of facts, plus one kind of question:


FormatMeaning
I p vI tell you Xp = v
I p q vI tell you Xp XOR Xq = v
Q k p1 p2...pkPlease tell me the value of Xp1 XOR Xp2 XOR...XOR Xpk

Input

There will be at most 10 test cases. Each case begins with two integers n and Q (1$ \le$n$ \le$20, 000, 2$ \le$Q$ \le$40, 000). Each of the following lines contains either a fact or a question, formatted as stated above. Thek parameter in the questions will be a positive integer not greater than 15, and thev parameter in the facts will be a non-negative integer less than220. The last case is followed byn = Q = 0, which should not be processed.

Output

For each test case, print the case number on its own line, then the answers, one on each one. If you can't deduce the answer for a particular question, from the facts I provide youbefore that question, print ``I don't know.", without quotes. If thei-th fact (don't count questions)cannot be consistent with all the facts before that, print ``The firsti facts are conflicting.", then keep silence for everything after that (including facts and questions). Print a blank line after the output of each test case.

Sample Input

2 6 
I 0 1 3
Q 1 0 
Q 2 1 0
I 0 2 
Q 1 1 
Q 1 0 
3 3 
I 0 1 6
I 0 2 2
Q 2 1 2
2 4 
I 0 1 7
Q 2 0 1
I 0 1 8
Q 2 0 1
0 0

Sample Output

Case 1: 
I don't know. 
3 
1 
2 

Case 2: 
4 

Case 3: 
7 
The first 2 facts are conflicting.

题意:

    有n(n<=20000)个未知的整数X0,X1,X2...Xn-1,有以下Q个(Q<=40000)操作:
    I p v :告诉你Xp=v
    I p q v :告诉你Xp Xor Xq=v
    Q k p1 p2 … pk : 询问 Xp1 Xor Xp2 .. Xor Xpk, k不大于15。
    如果当前的I跟之前的有冲突的话,跳出   
思路:并查集题目,深深的感到没好好做并查集的无力感,知道是并查集却不知道怎么下手,说一下思路:

1.对于每次的询问,我们并不需要知道每个数的大小也可以推出来结果,对于这种: I p v

的我们可以虚拟一个数xn=0,这样就可以有通式p^q=v,因为p^0=p。虚根xn是不能变的,它的子孙都有确定的值

2.我们假设偏移量val[i]=x[i]^x[fa[i]],还有熟悉a^b = 1 , b^c = 2 , 那么 a^c = 1^2 = 3,还有异或可以互相转化:a^b=c -> a^b^b=c^b -> a = b^c

3.为什么会用到并查集呢,因为对于同一个集合里的话我们可以通过他们与根的偏移量和根的值来知道两个数的异或结果,这样更方便计算,同时计算:Q k x1 .. xk 的时候,就可以转化为:(val[x1]^val[x2]..val[xk])^(x[fa[x1]]^x[fa[x2]]..x[fa[xk]]),然后利用异或偶数次不变的原理判断必须是奇数次才有可以得到结果,判断是不是xn根就是了

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <algorithm>
using namespace std;
const int MAXN = 20010;

int n, m;
int val[MAXN], fa[MAXN];

int find(int x) {
	if (x != fa[x]) {
		int tmp = fa[x];
		fa[x] = find(fa[x]);
		val[x] ^= val[tmp];
	}
	return fa[x];
}

int Union(int x, int y, int v) {
	int fx = find(x);
	int fy = find(y);
	if (fx == fy)
		return (val[x]^val[y]) == v;
	if (fx == n)
		swap(fx, fy);
	fa[fx] = fy;
	val[fx] = val[x]^v^val[y];
	return 1;
}

int main() {
	char str[MAXN];
	int p, q, v, k, x;
	int cas = 1;
	while (scanf("%d%d", &n, &m) != EOF && n+m) {
		for (int i = 0; i <= n; i++) {
			val[i] = 0;
			fa[i] = i;
		}
		printf("Case %d:\n", cas++);
		int facts = 0;
		int err = 0;
		while (m--) {
			scanf("%s", str);
			if (str[0] == 'I') {
				gets(str);
				facts++;
				if (err)
					continue;
				int cnt = sscanf(str, "%d%d%d", &p, &q, &v);
				if (cnt == 2) {
					v = q;
					q = n;
				}
				if (!Union(p, q, v)) {
					err = true;
					printf("The first %d facts are conflicting.\n", facts++);
				}
			} else {
				scanf("%d", &k);
				int ans = 0;
				int is = 1;
				map<int, int> mp;
				for (int i = 0; i < k; i++) {
					scanf("%d", &x);
					if (err)
						continue;
					int f = find(x);
					ans ^= val[x];
					mp[f]++;
				}
				if (err)
					continue;
				map<int, int>::iterator it;
				for (it = mp.begin(); it != mp.end(); it++) {
					if (it->second % 2) {
						if (it->first != n) {
							is = 0;
							break;
						}
						else ans ^= val[it->first];
					}
				}
				if (is)
					printf("%d\n", ans);
				else printf("I don't know.\n");
			}
		}
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值