X0 ~ Xn-1 共n个数,根据给定的信息,给出询问结果。
已知 I a b c 表示Xa ^ Xb = c,I a c表示Xa = c
询问Q K X1...Xk 求X1 ^ ...^ Xk 的结果。
1.令Xn = 0,将Xa = c转变成Xa ^ Xn = c,所以所有已知的数都和Xn在同一棵树(以n为根)
2.在询问时,X1 ^ ... Xk = Xf1 ^ ... Xfk ^ v[1] ^... ^ v[k]。其中Xfi未知,如果根出现的次数为偶数,则可消去,如果为奇数,如果Xfi的根(即Xi)的根为Xn,则数已知,可求,否则,就无法求出。
3.v[i]记录Xi与根Xfi的关系。
4.memset(v,0,sizeof(int) * n)就好了,不一定要到maxn的,特别是要经常初始化的。
只在乎奇偶的话^= 1也不错。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 2e5 + 50;
int f[maxn],v[maxn],cnt[maxn];
int n,q;
bool cft = false;
int find(int x)
{
if(f[x] == x) return x;
int tmp = f[x];
f[x] = find(f[x]);
v[x] ^= v[tmp];
return f[x];
}
void init(int n)
{
memset(v, 0, sizeof(int) * (n + 1));
for (int i = 0; i <= n; i ++) {
f[i] = i;
}
cft = false;
}
void merge(int a,int b,int c)
{
int fa = find(a);
int fb = find(b);
if(fa == fb) {cft = ((v[a] ^ v[b]) != c); return;}
if(fa > fb) swap(fa,fb);
f[fa] = fb;
v[fa] = v[a] ^ v[b] ^ c;
}
void query()
{
memset(cnt, 0, sizeof(int) * n);
int k,t,ans = 0,rt;
scanf("%d",&k);
for (int j = 0; j < k; j ++) {
scanf("%d",&t);
rt = find(t);
cnt[rt] ^= 1;
ans ^= v[t];
}
if(!cft){
for (int i = 0; i < n; i ++) {
if(cnt[i]) {printf("I don't know.\n");return;}
}
printf("%d\n",ans);
}
}
int main()
{
int cn = 0;
while (scanf("%d%d",&n,&q) != EOF) {
getchar();
if(n == 0 && q == 0) break;
printf("Case %d:\n",++cn);
init(n);
int th = 0;
char op;
int a = 0,b = 0,c = 0;
for (int i = 1; i <= q; i ++) {
scanf("%c",&op);
if(op == 'I')
{ th ++;
scanf("%d%d%c",&a,&b,&op);
if(op == ' '){scanf("%d",&c);getchar();}
else if(op == '\n') {c = b,b = n;}
if(!cft){
merge(a,b,c);
if(cft) printf("The first %d facts are conflicting.\n",th);
}
}
else {
query(); getchar();
}
}
printf("\n");
}
return 0;
}