借鉴cxlove思路, state[i]表示X[i]异或当前的祖先值,设X[r1]为X[i]之前祖先,X[r2]为现在祖先,路径压缩前
state[i] = X[i]^X[r1],state[r1] = X[r1]^X[r2], 路径压缩时令state[i] = state[i]^state[r1] = X[i]^X[r1]^X[r1]^X[r2] = X[i]^X[r2],所以路径压缩递推式成立,而对于给出的关系X[a]^X[b] = value,设ra和rb为代表元,如果ra等于rb,则判断state[a]^state[b]=X[a]^X[ra]^X[b]^X[rb] = X[a]^X[b]是否等于value,如果ra不等于rb,则合并这俩个集合,假设令fa[ra] = rb,则state[ra] 应等于X[ra]^X[rb] = X[a]^X[b]^value^X[ra]^X[rb] = state[a]^state[b]^value,对于给出关系X[i] = value,则可以添加一个虚拟节点X[n] = 0,这样就可以归为X[a]^X[b] = value的形式了
对于查询,把给出的X[i1],X[i2],....X[ik]按照代表元分类,对于代表元不为X[n]的元素,则其分类的数量如果为偶数,则可以退出X[j1]^X[j2]...X[jp] = state[j1]^state[j2]...state[jp],但是数量如果为奇数则此式子不成立,所以应该返回不知道,但对于代表元为X[n]的元素,因为X[n] = 0,所以上式恒成立,不用讨论奇偶
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>
#include <map>
#include <string>
#include <climits>
#include <set>
#include <string>
#include <sstream>
#include <utility>
#include <ctime>
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::getline;
using std::greater;
using std::endl;
using std::multimap;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> PAIR;
typedef multimap<int, int> MMAP;
const int MAXN(20010);
const int SIGMA_SIZE(130);
const int MAXM(110);
const int MAXE(200010);
const int MAXH(18);
const int INFI((INT_MAX-1) >> 2);
const int BASE(131);
const ULL LIM(1000000000000000);
MMAP mmp;
int rec[MAXN], count;
int arr[MAXN];
struct FIND_SET
{
int fa[MAXN], state[MAXN];
int n;
void init(int tn)
{
n = tn;
for(int i = 0; i <= n; ++i)
{
fa[i] = i;
state[i] = 0;
}
}
int find(int sour)
{
if(fa[sour] == sour)
return sour;
int tf = fa[sour];
fa[sour] = find(tf);
state[sour] ^= state[tf];
return fa[sour];
}
int Union(int op1, int op2, int value)
{
int f1 = find(op1), f2 = find(op2);
if(f1 == f2)
{
if((state[op1]^state[op2]) != value)
return -1;
else
return 1;
}
if(f1 == n) swap(f1, f2);
fa[f1] = f2;
state[f1] = state[op1]^state[op2]^value;
return 0;
}
int query(int qn)
{
int ret = 0;
mmp.clear();
count = 0;
for(int i = 0; i < qn; ++i)
{
int tf = find(arr[i]);
if(mmp.find(tf) == mmp.end())
rec[count++] = tf;
mmp.insert(PAIR(tf, state[arr[i]]));
}
for(int i = 0; i < count; ++i)
{
if((mmp.count(rec[i])&1) && rec[i] != n)
return -1;
MMAP::iterator iter = mmp.lower_bound(rec[i]);
while(iter != mmp.end() && iter->first == rec[i])
{
ret ^= iter->second;
++iter;
}
}
return ret;
}
};
FIND_SET fs;
string str;
int main()
{
int n, q, n_case(0);
while(scanf("%d%d", &n, &q), n+q)
{
printf("Case %d:\n", ++n_case);
fs.init(n);
char flag;
int op[3], facts(0);
bool error(false);
for(int i = 0; i < q; ++i)
{
scanf(" %c", &flag);
if(flag == 'I')
{
++facts;
getline(cin, str);
if(error)
continue;
istringstream in(str);
int temp = 0;
while(in >> op[temp])
++temp;
if(temp == 2)
{
op[2] = op[1];
op[1] = n;
}
if(fs.Union(op[0], op[1], op[2]) == -1)
{
printf("The first %d facts are conflicting.\n", facts);
error = true;
}
}
else
{
int temp;
scanf("%d", &temp);
for(int j = 0; j < temp; ++j)
scanf("%d", arr+j);
if(error)
continue;
int ans = fs.query(temp);
if(ans == -1)
printf("I don't know.\n");
else
printf("%d\n", ans);
}
}
printf("\n");
}
return 0;
}