题意:
题目将以这样的形式进行提供已知条件或者提问,
分析:首先可以想到的是可以用并查集来做。
题目的是x1^x2^x3^……式子的值,
那么首先就要考虑俩个问题了:
1):如何记录x[]元素之间的关系
2):怎样传递元素之间的关系
这里我们注意到异或运算的性质:
对于a,b,c有:a xor b == c 和 a xor c == b 和 b xor c == a 等价,a^a==0
因此:我们用r[]数组保存该元素与根节点异或运算的关系;
接下来,为了方便处理,我们定义一个虚点xn,r[xn]=0,这样,只要根节点为xn的元素,这对于的具体也是已知的,同时,r[]的值就是其具体的值;而且,有一个好处就是,当进行I p v 操作时,相当于合并Union(p,n,v);
在压缩路径过程中,用r[x]^=r[f[x]] 求出与根节点的关系;
在判断能否计算出式子的值时,我们发现,根节点不为xn的元素,该集合必须出现偶数个的元素,否则该式子的具体值无法计算;
接下来就是读入数据的问题,额,我的方法比较笨……
基本已经可以实现了,看代码吧:
#include<iostream> #include<algorithm> #include<string.h> using namespace std; int f[20010],r[20010],n; int map[20010]; int xp[20],ans; void init() { for(int i=0;i<=n;i++) { f[i]=i; r[i]=0; } } int find(int x) { if(x==f[x]) return x; int t=find(f[x]); r[x]^=r[f[x]];//根据x与父节点的关系求出x与根节点的关系 f[x]=t; return f[x]; } bool Union(int x,int y,int k) { int a=find(x); int b=find(y); if(a==b) { if((r[x]^r[y])==k) return true; return false; } if(a==n) swap(a,b); f[a]=b; r[a]=r[x]^r[y]^k; return true; } bool query(int m) { memset(map,0,sizeof(map)); for(int i=0;i<m;i++) { map[find(xp[i])]++; ans^=r[xp[i]]; } int flag=0; for(int i=0;i<m;i++) { int t=find(xp[i]); if(map[t]%2!=0 && t!=n) {flag=1;break;} } if(flag) return false; return true; } int main() { char s[2],c; int a,b,v,Q,cas=0; while(scanf("%d %d",&n,&Q)==2 &&(n||Q)) { init(); printf("Case %d:\n",++cas); int fact=0,flag=0; while(Q--) { scanf("%s%d%d",s,&a,&b); if(s[0]=='I') { fact++; c=getchar(); if(c==' ') { scanf("%d",&v); if(flag)continue; if(!Union(a,b,v)) { printf("The first %d facts are conflicting.\n",fact); flag=1; } } else { if(flag)continue; if(!Union(a,n,b)) { printf("The first %d facts are conflicting.\n",fact); flag=1; } } } else { xp[0]=b; for(int i=1;i<a;i++) scanf("%d",&xp[i]);//额,这里有点多此一举 if(flag)continue; ans=0; if(query(a)) printf("%d\n",ans); else printf("I don't know.\n"); } } printf("\n"); } return 0; }