【uva12232/hdu3461】带权并查集维护异或值

题意:

对于n个数a[0]~a[n-1],但你不知道它们的值,通过逐步提供给你的信息,你的任务是根据这些信息回答问题:
I P V :告诉你a[P] = V
I P Q V:告诉你a[P] XOR a[Q] = V
Q K P1..PK:询问a[P1]^a[P2]^...a[PK]的值
n<=20000

题解:
 
首先看前两个操作:
第一个操作我们可以新加一个节点a[n]=0,则a[p]=val转化为a[p]^a[n]=val。
那么所有知道值的点必定都与a[n]在同一个并查集之内。
 
我们可以用带权并查集,对每个点x维护fa[x],d[x]是a[x]^a[fa[x]]。
对与第三个操作,我们可以发现p1,p2,...,pk必定在某几个并查集之中。
如果某个并查集中有奇数个p,那就相当于a[p1]^a[p2]^..a[px] ^ 奇数次a[根](异或一个数偶数次相当于没有异或它)。
如果根不是a[n],也就是根的值未知,那么必定是不确定答案的。
否则我们就可以直接算出。

注意合并的时候如果有一个是a[n]所在集合,要让a[n]为根。

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<ctime>
 6 using namespace std;
 7 
 8 const int N=20100;
 9 int n,m,fa[N],d[N],cnt[N],q[N];
10 char s[10];
11 
12 int findfa(int x)
13 {
14     if(fa[x]!=x)
15     {
16         int xx=fa[x];
17         fa[x]=findfa(fa[x]);
18         d[x]=d[x]^d[xx];
19     }
20     return fa[x];
21 }
22 
23 int main()
24 {
25     freopen("a.in","r",stdin);
26     freopen("a.out","w",stdout);
27     char ch;
28     int x,y,k,p,xx,yy,val,ans,bk,ok,num,T=0;
29     while(1)
30     {
31         scanf("%d%d",&n,&m);
32         if(!n && !m) break;
33         printf("Case %d:\n",++T);
34         memset(cnt,0,sizeof(cnt));
35         for(int i=0;i<=n;i++) fa[i]=i,d[i]=0;
36         num=0;bk=1;
37         for(int i=1;i<=m;i++)
38         {
39             scanf("%s",s);
40             if(s[0]=='I')
41             {
42                 num++;
43                 scanf("%d%d%c",&x,&y,&ch);
44                 if(ch==' ') scanf("%d",&val);
45                 else val=y,y=n;
46                 if(!bk) continue;
47                 xx=findfa(x);yy=findfa(y);
48                 if(xx!=yy)
49                 {
50                     if(xx==n) swap(x,y),swap(xx,yy);//debug
51                     fa[xx]=y;
52                     d[xx]=val^d[x];
53                 }
54                 else if((d[x]^d[y])!=val) {printf("The first %d facts are conflicting.\n",num);bk=0;}
55             }
56             else
57             {
58                 scanf("%d",&k);
59                 for(int j=1;j<=k;j++)
60                 {
61                     scanf("%d",&q[j]);
62                     findfa(q[j]);
63                     cnt[fa[q[j]]]++;                    
64                 }
65                 if(!bk) continue;
66                 ans=0;ok=1;
67                 for(int j=1;j<=k;j++)
68                 {
69                     x=q[j];
70                     if(fa[x]!=n && (cnt[fa[x]]&1)) {printf("I don't know.\n");ok=0;break;}
71                     ans^=d[x];
72                 }
73                 for(int j=1;j<=k;j++) cnt[fa[q[j]]]--;
74                 if(ok) printf("%d\n",ans);
75             }
76             // printf("i = %d\n",i);
77             // for(int j=0;j<n;j++) printf("%d  fa = %d  d = %d\n",j,fa[j],d[j]);
78             // printf("\n");
79         }
80         printf("\n");
81     }
82     return 0;
83 }

 

 
posted @ 2016-11-08 19:16  拦路雨偏似雪花  阅读(327)  评论(0编辑  收藏  举报