扩展的并查集,参考了以下两个,结合了一下,然后对Query的部分有一些改动,主要是用了map来判断出现次数的奇偶

http://www.cppblog.com/Yuan/archive/2010/09/02/125667.html?opt=admin

http://blog.csdn.net/acm_cxlove/article/details/8101710

 

X1...Xn-1,这是题中所说的未给出的n个数,维护一个带权的并查集,每个点有一个权w

保证有w[k] = Xk ^ Xfa[k];  Xfa[k]表示Xk的父亲。

 

对于

I p q v

则对p, q进行Union操作,并利用v维护各自的权w

对于

I p v

可以加入虚拟节点n,令Xn = 0; 这样任意以该节点为父亲的节点均有 w[k] = Xk;

这样就转化成I p n v了

而对于每次查询

Q k p1 p2 ... pk

结果ans = Xp1 ^ Xp2 ^ ...  ^ Xpk = w[p1] ^ w[p2] ^ ... ^ w[pk] ^ (Xfa[p1] ^ Xfa[p2] ^ ... ^ Xfa[pk]).

这里利用了性质:

任取整数a,有

a ^ a = 0;

a ^ 0 = a;

又因为 w[p1] ... w[pk] 是已知的, 只需判断 Xfa[p1] ... Xfa[pk] 是否已知即可,即看这些节点是否以Xn为根。

注意的一点是Xfa[p1] ... Xfa[pk] 中会有重复的,只要出现了偶数次就不用计算,只用考虑出现奇数次的就行了。

另一点注意的是输入输出的形式以及输入行尾换行符的处理,我就在这个地方WA了n多次= =

View Code
  1 #include<iostream>
  2 #include<stack>
  3 #include<cstring>
  4 #include<cstdio>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<map>
  8 using namespace std;
  9 
 10 const int N = 20000 + 1;
 11 const int K = 15;
 12 const int LINELEN = 150;
 13 
 14 int fa[N], w[N];
 15 int n,q;
 16 int nfacts;
 17 char line[LINELEN];
 18 
 19 void init()
 20 {
 21     for(int i = 0; i<= n; i++)
 22         fa[i] = i;
 23     memset(w, 0, sizeof(w));
 24 
 25     nfacts = 0;
 26 }
 27 
 28 int Find(int x)
 29 {
 30     if(x != fa[x])
 31     {
 32         int t = fa[x];
 33         fa[x] = Find(fa[x]);
 34         w[x] ^= w[t];
 35     }
 36     return fa[x];
 37 }
 38 
 39 bool Union(int p, int q, int v)
 40 {
 41     int rp = Find(p);
 42     int rq = Find(q);
 43     if(rp == rq)
 44     {
 45         return  v == (w[p] ^ w[q]);
 46     }
 47 
 48     if(rp == n) swap(rp,rq);
 49 
 50     fa[rp] = rq;
 51     w[rp] = w[p] ^ w[q] ^ v;
 52     return true;
 53 }
 54 
 55 bool info(int a, int b, int c)
 56 {
 57     bool rt = Union(a, b, c);
 58     if(!rt)
 59         printf("The first %d facts are conflicting.\n", nfacts);
 60     return !rt;
 61 }
 62 
 63 int main(int argc, char *argv[])
 64 {
 65 #ifdef ACM
 66     freopen("ttwo.in", "r", stdin);
 67 #endif // ACM
 68 
 69     int ncase = 1;
 70     while(scanf("%d %d", &n, &q), n != 0 || q != 0)
 71     {
 72         printf("Case %d:\n", ncase++);
 73         init();
 74         bool conflict = false;
 75 
 76         while(q--)
 77         {
 78             char tp[5];
 79             scanf("%s", tp);
 80             if(tp[0] == 'I')
 81             {
 82                 nfacts++;
 83                 getchar();gets(line);
 84                 int a, b, c;
 85                 int rt = sscanf(line, "%d %d %d", &a, &b, &c);
 86                 if(rt == 2)
 87                 {
 88                     c = b; b = n;
 89                 }
 90 
 91                 if(conflict) continue;
 92 
 93                 conflict = info(a, b, c);
 94             }
 95             else if(tp[0] == 'Q')
 96             {
 97                 int k;
 98                 int para;
 99                 map<int, bool> fas;
100                 bool known = true;
101                 int ans = 0;
102 
103                 scanf("%d", &k);
104                 for(int i = 0; i!= k; i++)
105                 {
106                     scanf("%d", &para);
107 
108                     if(conflict) continue;
109 
110                     fas[Find(para)] = !fas[Find(para)];
111                     ans ^= w[para];
112                 }
113 
114                 if(conflict) continue;
115 
116                 for(map<int, bool>::iterator it = fas.begin(); it != fas.end(); it++)
117                 {
118                     if(it->second)
119                     {
120                         ans ^= w[it->first];
121                         if(!(known = (Find(it->first) == n)))
122                             break;
123                     }
124                 }
125 
126                 if(!known)
127                 {
128                     puts("I don't know.");
129                 }
130                 else
131                 {
132                     printf("%d\n", ans);
133                 }
134             }
135         }
136 
137         putchar('\n');
138     }
139 
140     return 0;
141 }

 

BTW,做惯了USACO,发现对这种复杂的IO真心不习惯了= =,WA了何止10次啊.............= =

最后的问题竟然是.............Case的C忘了大写= =...........................................