Exclusive-OR
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2270 Accepted Submission(s): 634
Problem Description
You are
not given
n non-negative integers
X0, X1, ..., Xn-1 less than 2
20 , 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:
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:

Input
There will be at most 10 test cases. Each case begins with two integers
n and
Q (1 <=
n <= 20,000, 2 <=
Q <= 40,000). Each of the following lines contains either a fact or a question, formatted as stated above. The
k parameter in the questions will be a positive integer not greater than 15, and the
v parameter in the facts will be a non-negative integer less than 2
20. The last case is followed by
n=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 you
before that question, print "I don't know.", without quotes. If the
i-th fact (don't count questions)
cannot be consistent with
all the facts before that, print "The first i 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.
Source
Recommend
题意:
有n个小于2^20的非负整数x0, x1, x2 .. xn-1。但你并不知道他们的值,我会逐步提供一些信息,你任务是根据这些信息回答问题。
I p v 告诉你Xp = v
I p q v 告诉你 Xp ^ Xq = v
Q k q1 q2 .. qk 询问 q1 ^ q2 ^ .. qk 的值
d[x] 表示x与父节点的异或值 : d[x] = val[x] ^ val[fa[x]]
有异或的性质可得 路径压缩的时候 d[x] = d[x] ^ d[fa[x]]
对于操作
I a v 额外建立一个节点,这里是n,val[n] 永远为0,则把a所在堆和n合并,并按照上面所说的那样维护d值
I a b v 如果ab根节点相同,并且d[a] ^ d[b] != v 值有矛盾,返回。否则直接合并a b所在堆,并维护d值
Q k q1 q2 .. qk 求出q1 q2 ... qk 的根节点 ri r2 ... rk,然后根据根节点计算:
如果有偶数个节点,比如 q1 q3 q6 q7的根节点都是r4,那么
d[q1] ^ d[q3] ^ d[q6] ^ d[q7] = ( q1 ^ r4 ) ^ ( q3 ^ r4) ^ ( q6 ^ r4 ) ^ ( q7 ^ r4)
= q1 ^ q3 ^ q6 ^ q7
但是如果是奇数个的情况最后会多出一个根节点,如果根节点不是n(因为val[n] = 0),则不能计算出值。
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));
const int maxn = 20000 + 20;
int fa[maxn], d[maxn];
int n;
int find(int x) {
if(fa[x] == x) return x;
int y = find(fa[x]);
d[x] = d[x] ^ d[fa[x]];
return fa[x] = y;
}
bool Union(int a, int b, int v) {
int pa = find(a);
int pb = find(b);
if(pa == pb) {
return (d[a] ^ d[b]) == v;
}
if(pa == n) swap(pa, pb);
fa[pa] = pb;
d[pa] = d[a] ^ d[b] ^ v;
return true;
}
struct Node {
int a, p;
bool operator < ( const Node & b ) const {
return p < b.p;
}
} quy[30];
int query(int k) {
for(int i=0; i<k; i++) {
quy[i].p = find(quy[i].a);
}
sort(quy, quy+k);
int l = 0;
int ans = 0;
while(l < k) {
int r = l;
while(r < k-1 && quy[r+1].p == quy[l].p) r++;
int num = r - l + 1;
if(quy[l].p != n && num&1) return -1;
for(int i=l; i<=r; i++) ans ^= d[quy[i].a];
l = r + 1;
}
return ans;
}
char str[100];
int main() {
int Q;
int kase = 1;
while(scanf("%d%d", &n, &Q) != EOF && n+Q) {
for(int i=0; i<=n; i++) fa[i] = i, d[i] = 0;
printf("Case %d:\n", kase++);
int killId = -1;
int kk = 0;
while(Q--) {
scanf("%s", str);
if(str[0] == 'Q') {
int k;
scanf("%d", &k);
for(int i=0; i<k; i++) scanf("%d", &quy[i].a);
if(killId != -1) continue;
int ans = query(k);
if(ans == -1) puts("I don't know.");
else printf("%d\n", ans);
} else {
kk++;
gets(str);
if(killId != -1) continue;
int a, b, c;
int t = sscanf(str, "%d%d%d", &a, &b, &c);
int res;
if(t == 2) {
res = Union(a, n, b);
} else {
res = Union(a, b, c);
}
if(!res) killId = kk;
}
}
if(killId != -1) {
printf("The first %d facts are conflicting.\n", killId);
}
putchar('\n');
}
return 0;
}