Exclusive-OR hdu3234

借鉴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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值