您的位置:首页 > 其它

uva12232 - Exclusive-OR 加权并查集

2014-02-27 18:48 465 查看
You are not given n non-negative integers
X0, X1,..., Xn-1 less than
220, 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:

FormatMeaning
I
p v
I tell you
Xp = v
I
p q v
I tell you
Xp XOR Xq = v
Q
k p1 p2...pk
Please tell me the value of
Xp1 XOR Xp2 XOR...XOR Xpk

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
220. 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.

告诉你Xp=v或者Xp^Xq=v,询问一些Xi的异或值。

如果没有Xp=v,只告诉你Xp^Xq=v就容易一些。只需要把Xp和Xq合并,设w[i]为Xi和它父节点的异或值,合并的时候注意w[i]=w[i]^w[p[i]]。查询的时候Xp1^Xp2...^Xpk=w[Xp1]^rootp1^w[Xp2]^rootp2...^w[Xpk]^rootpk,所以只要把w[Xpi]都异或上,由于root的具体值都是不知道的,于是若所有root都是偶数个,抵消了,答案就是w[Xpi]的异或。否则是不能算出答案的。

告诉你Xp=v怎么办呢?这是个难点,要设置一个节点N,假设Xpn=0。把p和N合并,而且要保证N这个点一直是作为根节点。也就是说最后和N一个集合的X的值都是知道的,并且N是根节点。判断root奇偶的时候,若是N作为节点这个root就无所谓,因为这个值是知道的,就是0。也就是说除了N以外作为根的节点若出现奇数次,就无法确定答案。

注意用异或符号的时候最好打括号。

#include<cstring>
#include<cstdio>
#include<iostream>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#define INF 0x3f3f3f3f
#define MAXN 20010
#define MAXM 3010
using namespace std;
int N,Q,bug,p[MAXN],w[MAXN];
char str[20];
int find(int x){
if(p[x]==x) return x;
int root=find(p[x]);
w[x]^=w[p[x]];
return p[x]=root;
}
void Union(int a,int b,int v){
int x=find(a),y=find(b);
if(x==y){
if((w[a]^w[b])!=v) bug=1;   //这里如果不打括号就是错的
return;
}
if(x==N) swap(x,y);      //N要始终作为根节点
p[x]=y;
w[x]=w[a]^w[b]^v;
}
int main(){
freopen("in.txt","r",stdin);
int cas=0;
while(scanf("%d%d",&N,&Q),N||Q){
printf("Case %d:\n",++cas);
for(int i=0;i<=N;i++) p[i]=i;
memset(w,0,sizeof(w));
int k=0;
bug=0;
while(Q--){
int a,b,v;
scanf("%s",str);
if(str[0]=='I'){
k++;
gets(str);
if(bug) continue;
if(sscanf(str,"%d%d%d",&a,&b,&v)==2){
v=b;
b=N;
}
Union(a,b,v);
if(bug) printf("The first %d facts are conflicting.\n",k);
}
else{
int K,t,ans=0,know=1;
map<int,int> Map;
map<int,int>::iterator it;
scanf("%d",&K);
while(K--){
scanf("%d",&t);
int x=find(t);
ans^=w[t];
Map[x]++;
}
if(bug) continue;
for(it=Map.begin();it!=Map.end();it++) if(it->second%2){
if(it->first!=N){
know=0;
break;
}
}
if(know) printf("%d\n",ans);
else printf("I don't know.\n");
}
}
puts("");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: