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
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,X2Xn-1,有以下Q个(Q<=40000)操作:
I p v :告诉你Xp=v
I p q v :告诉你Xp ^ Xq=v
Q k p1 p2 … pk : 询问 Xp1 Xor Xp2 .. Xor Xpk, k不大于15。
如果当前的I跟之前的有冲突的话,跳出
思路:
并查集,每个节点记录与根节点的异或偏移量,一个集合内如果有一个知道值了的话,这个集合里面都能知道值,(可以标记根是否已经得到值,或者像网上大部分人的做法,虚拟出一个节点n,值为0,将I操作统一)查询时,如果一个未知集合出现了偶数个,那么可以得到其值,u^root^v^root=u^v,如果出现奇数次,那么不能得到。Merge的时候有个小坑,见代码。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <string> #include <map> #include <stack> #include <vector> #include <set> #include <queue> #include<sstream> #define maxn 20005 #define MAXN 100005 #define mod 100000000 #define INF 0x3f3f3f3f #define pi acos(-1.0) #define eps 1e-8 typedef long long ll; using namespace std; int n,m,ans,cnt,tot,flag; int pre[maxn],px[maxn],val[maxn],vis[maxn]; vector<int>root,q[16]; char s[5],buff[100]; int Find(int x) { if(x==pre[x]) return x; int r=pre[x]; pre[x]=Find(pre[x]); px[x]=px[r]^px[x]; return pre[x]; } bool Merge(int u,int v,int w) { int x=Find(u),y=Find(v); if(x!=y) { if(vis[x]||vis[y])// 如果有集合知道值 必须以知道值集合的根为根 { if(!vis[y]) swap(x,y); } pre[x]=y; px[x]=w^px[u]^px[v]; } else { if((px[u]^px[v])!=w) return false ; } return true ; } void update() { int u,v,w; cnt++; gets(buff); stringstream si; si.clear(); si.str(buff); si>>u; si>>v; if(si>>w) { u++,v++; if(flag) return ; if(!Merge(u,v,w)) { flag=1; printf("The first %d facts are conflicting.\n",cnt); } } else { if(flag) return ; u++; int r=Find(u); if(vis[r]) { if(val[r]!=(v^px[u])) { flag=1; printf("The first %d facts are conflicting.\n",cnt); } } else { vis[r]=1; val[r]=v^px[u]; } } } void query() { int i,j,u,v,k,r,flg; scanf("%d",&k); root.clear(); for(i=0;i<k;i++) q[i].clear(); for(i=1; i<=k; i++) { scanf("%d",&u); u++; int r=Find(u); flg=0; for(j=0;j<root.size();j++) { if(r==root[j]) { flg=1; q[j].push_back(u); break ; } } if(!flg) { root.push_back(r); q[root.size()-1].push_back(u); } } if(flag) return ; flg=0; int res=0; for(i=0;i<root.size();i++) { if(vis[root[i]]) { for(j=0; j<q[i].size(); j++) { res^=(px[q[i][j]]^val[root[i]]); } } else { if(q[i].size()%2==1) { flg=1; break ; } else { for(j=0; j<q[i].size(); j+=2) { u=px[q[i][j]]^px[q[i][j+1]]; res^=u; } } } } if(flg) printf("I don't know.\n"); else printf("%d\n",res); } int main() { int i,j,t,u,v,w,test=0; while(~scanf("%d%d",&n,&m)) { if(n==0&&m==0) break ; for(i=1; i<=n; i++) { pre[i]=i; px[i]=vis[i]=0; } flag=cnt=0; printf("Case %d:\n",++test); for(i=1; i<=m; i++) { scanf("%s",s); if(s[0]=='I') update(); else query(); } puts(""); } return 0; }