题目:Exclusive-OR
思路:
并查集。
先将 I p v 的格式转化成 I p n v ,其中n为一个虚拟的根节点,在此后,n一定也要做根节点。然后就可以借助并查集来记录两数之间的关系。其中 fa[i] 记录 i 的根, d[i]=i ^ fa[i] 。如果x、y共一个根节点,那么 x^y = x^fa^y^fa = d[x]^d[y] 。对于每一个询问,要知道它是否可求,里面的例如 x^a^a^y 可以直接简化成 x^y ,而那些和n相连的数,数值都是可求的,不用考虑。剩下的那些数,并不需要都共一个根节点,这些数,如果都是两个、四个、六个等偶数个共一个根节点的话,异或值是可以求的。如果有一组供着跟姐点的数是奇数个的话,假设是5个:x1^x2^x3^x4^x5,就会变成 d[x1]^d[x2]^d[x3]^d[x4]^x5 ,此时,由于x5的值不可求,所以无法求出。
代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <stack>
#include <queue>
#include <deque>
#include <set>
#include <cstring>
#include <map>
using namespace std;
int n,Q;
int fa[20005]= {0}; //根节点
int d[20005]= {0}; //到根节点的距离
int find(int x) { //并查集中查找根节点
if(fa[x]==x) return x;
int y=fa[x];
fa[x]=find(fa[x]);
d[x]=d[x]^d[y];
return fa[x];
}
void Do(vector<int>& a,vector<int>& c) {
sort(a.begin(),a.end());
for(int i=1; i<a.size(); i++) { //去掉重复的
if(a[i]==a[i-1]) a[i]=a[i-1]=-1;
}
vector<int> b;
for(int i=0; i<a.size(); i++) {
if(a[i]!=-1) {
if(find(a[i])==n) c.push_back(a[i]); //根节点为n
else b.push_back(a[i]);
}
}
a=b;
}
bool judge(int cnt[]) {
for(int i=0; i<n; i++) {
if(cnt[i]&1) return false; //以i为根的点不能为奇数
}
return true;
}
int main() {
int T=0;
while(~scanf("%d%d",&n,&Q)&&n!=0) {
for(int i=0; i<=n; i++) {
fa[i]=i;
}
memset(d,0,sizeof(d));
int t=0;
bool flag=true;
printf("Case %d:\n",++T);
for(int i=0; i<Q; i++) {
char opr;
while(scanf("%c",&opr)&&!isalpha(opr));
if(opr=='I') {
t++;
char s[101]= {0};
fgets(s,100,stdin);
int x,y,z;
if(sscanf(s,"%d%d%d",&x,&y,&z)!=3) {
z=y,y=n; //将此看做把这个已知值的数挂在一个虚拟节点n上,I p v -> I p n v
}
if(flag==true) {
int fa1=find(x),fa2=find(y);
if(fa1==fa2) {
if(z!=(d[x]^d[y])) { //矛盾
flag=false;
printf("The first %d facts are conflicting.\n",t);
}
} else {
if(fa1==n) swap(x,y),swap(fa1,fa2); //节点n一定要做根
fa[fa1]=fa2;
d[fa1]=d[x]^d[y]^z;
}
}
} else {
int k;
int cnt[20005]= {0};
int ans=0;
vector<int> a,c;
scanf("%d",&k);
for(int j=0; j<k; j++) {
int x;
scanf("%d",&x);
a.push_back(x);
}
if(flag) {
Do(a,c); //将重复的数去掉后,c中为根为n的数,a为其他的数
for(int j=0; j<a.size(); j++) {
find(a[j]);
cnt[fa[a[j]]]++;
ans=ans^d[a[j]];
}
for(int j=0; j<c.size(); j++) {
ans^=d[c[j]];
}
if(!judge(cnt)) {
printf("I don't know.\n");
} else {
printf("%d\n",ans);
}
}
}
}
printf("\n");
}
return 0;
}