UVA 12232 Exclusive-OR 并查集

UVA 12232

题意:I p v,表示把p设为v,I p q v,表示p^q设为v,Q K p1,p2,...pk 表示求p1^p2^...^pk的值

思路:经典并查集,设f[ a ]为a和a的父亲的异或(由于路劲压缩,它的父亲就是根节点),设a的父亲为fa,b的父亲为fb,则

r[ a ]=a^fa,r[ b ]=b^fb,如果题目设a^b=c,那么找到a,b的父亲(就是根)fa,fb,然后把fb设为fa的父亲,则此时

r[ fa ]=fa^fb=r[ a ]^r[ b ]^a^b=r[ a ]^r[ b ]^c,如果设a=c,那么就把a的根节点连接一个特殊节点,特殊节点值为0,那么如何查询a^b呢,如果a和b的根同为root,那么r[ a ]^r[ b ]=a^root^b^root=a^b,明显他们的根消失了,也就是说,如果查询偶数个同根的数异或值,他们的根root会消掉,答案就是他们的r[ pi ]的异或,奇数个同根的数由于多了个未知的根节点(特殊节点为0除外),无解。

闲扯一点,原谅我英语不是那么的好,函数命名从来都是凭感觉...

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=20000+5;
int f[maxn],r[maxn],num[20],vis[20];
int n,flag,tot;
char s[maxn];
void init()
{
	for(int i=0;i<maxn;i++)
	{
		f[i]=i;
		r[i]=0;
	}
	flag=0;
}
int find(int a)
{
	if(f[a]!=a)
	{
		int fa=f[a];
		f[a]=find(fa);
		r[a]^=r[fa];//由于r[a]本来就是a^fa,而路劲压缩使得r[fa]=fa^root,所以此时r[a]=a^root; 
	}
	return f[a];
}
int link(int a,int b,int c)
{
	int fa=find(a),fb=find(b);
	if(fa==fb)
	{
		if((r[a]^r[b])!=c)//冲突,同根的a,b的r[a]^r[b]就是a^b 
		return 0;
		return 1;
	}
	if(fa==n)
	swap(fa,fb);
	f[fa]=fb;
	r[fa]=r[a]^r[b]^c;
	return 1;
}
int query()
{
	int i,j,ans=0;
	memset(vis,0,sizeof(vis));
	for(i=1;i<=tot;i++)
	{
		if(vis[i]==1)
		continue;
		int root=find(num[i]);
		int sum=0;
		for(j=1;j<=tot;j++)
		if(!vis[j]&&root==find(num[j])) 
		{
			ans^=r[num[j]];
			sum++;
			vis[j]=1;
		}
		if(root!=n&&sum%2==1)//基数个同根节点异或误解 
		return -1;
	}
	return ans;
}
int main()
{
	int m,kase=0;
	while(~scanf("%d%d",&n,&m),m+n)
	{
		int i,p,q,v,cnt=0;
		printf("Case %d:\n",++kase);
		init();
		while(m--)
		{
			scanf("%s",s);
			if(flag)
			{
				gets(s);
				continue;
			}
			if(s[0]=='I')
			{
				cnt++;
				gets(s);
				if(sscanf(s,"%d%d%d",&p,&q,&v)==2)
				{
					v=q;
					q=n;
				}
				if(!link(p,q,v))
				{
					printf("The first %d facts are conflicting.\n",cnt);
					flag=1;
				}
			}
			else
			{
				scanf("%d",&tot);
				for(i=1;i<=tot;i++)
				scanf("%d",&num[i]);
				int ans=query();
				if(ans==-1)
				printf("I don't know.\n");
				else
				printf("%d\n",ans);
			}
		}
		printf("\n");
	}
}

猜你喜欢

转载自blog.csdn.net/ccsu_cat/article/details/80587374