poj1703(并查集维护不同集合关系的方法)

/*
translation:
	已知所有元素要么属于第一个集合,要么属于第二个集合,给出两种操作。第一种是D a b,表示
	a,b两个元素不在一个集合里面。第二种操作是A a b,表示询问a,b两个元素是否在同一个集合
	里面。如果不能确定的话打印not sure。否则给出答案。
solution:
	并查集。
	这道题有点类似poj1182(食物链),两题的关键点都在于如何维护不同集合的关系。并查集的功能
	正好与之相反,是维护相同集合间的关系。如何用并查集来实现不同集合的维护呢?方法是改变集
	内元素的类型。本来unite(a,b)表示a,b属于同一个集合,现在用unite(a,b+n)来表示a,b属
	于不同集合,即a属于第一个集合,b属于第二个集合。同理unite(a+n,b)表示a属于第二个集合
	b属于第一个集合。每次要D操作时,将所有可能都unite。
note:
	*并查集维护不同集合间的关系
date:
	2016.10.17
*/
#include 
#include 
#include 

using namespace std;
const int maxn = 1e5 + 5;

int n, m;
int par[maxn*2], high[maxn*2];

void init(int n)
{
	for(int i = 1; i <= n; i++)
	{
		par[i] = i;
		high[i] = 0;
	}
}

int getRoot(int x)
{
	return par[x] == x ? x : par[x] = getRoot(par[x]);
}

void unite(int x, int y)
{
	x = getRoot(x);
	y = getRoot(y);
	if(x == y)	return;

	if(high[x] < high[y])	par[x] = y;
	else
	{
		par[y] = x;
		if(high[x] == high[y])	high[x]++;
	}
}

bool same(int x, int y)
{
	return getRoot(x) == getRoot(y);
}

int main()
{
	//freopen("in.txt", "r", stdin);
    int T;
    scanf("%d", &T);
    while(T--)
	{
		scanf("%d%d", &n, &m);
		init(2*n);

		char op;	int a, b;
		for(int i = 1; i <= m; i++)
		{
			scanf("\n%c%d%d", &op, &a, &b);
			if(op == 'D')
			{
				unite(a, b+n);
				unite(a+n, b);
			}
			else
			{
				if(same(a, b+n) || same(a+n, b))	printf("In different gangs.\n");
				else if(same(a, b) || same(a+n, b+n))	printf("In the same gang.\n");
				else	printf("Not sure yet.\n");
			}
		}
	}
    return 0;
}

你可能感兴趣的:(=====数据结构=====,并查集)