poj 1703 Find them, Catch them (分组并查集 偏移向量实现)

前段时间做了不少并查集的题目,前天又接触了一种新的类型——分组类型的并查集,通常解法就是加一个偏移量,查了很多资料看了很多的并查集相关的解释终于把向量偏移给搞明白了,不得不说这个向量偏移的名字起的真是经典,完全就是借用了向量的思维。一般的分组并查集分组都不是很多(假设为n组),这个时候通常有两中不同的解法:1.n个并查集,合并一类节点时根据分组信息合并两次,查找的时候也多查一次。2、加个偏移向量数组,在合并和查找时记得要及时的更新偏移量数组。当然第二种方法就高效了很多。

 

本题正是利用了第二种方法来解,由于只有两组,所以偏移向量只要记录0或者1就可以了,当然这里如果不取余直接记录真实的偏移量也是可以的,但在最后查找判断的时候也少不了取余判断这一步。查找的时候更新偏移量是很好理解的,直接就是向量加然后取余,a->faa的根节点时fa),那么在查找的时候,要把a直接连接在fa的父节点上的,这个时候根据向量关系就可以得到offset[a] = offset[a] + offset[fa],这里offset[a]表示从a到其根节点的偏移量,所以在这里查找的之前要先把a的根节点保存下来,因为路径压缩的时候其根节点就变成其新的根节点了。当然因为本题只有两组,所以加个取余就可以了。然后就是合并的时候的更新问题,在合并的的时候本题就是两组即要合并的两点属于不同的组,即如果aoffset0的组那么b就在offset1的组,反之亦然,所以他们的偏移量差就是1,那么在合并的时候就要利用向量运算来合并了,假设

a->fa,b->fba的根节点是fab的根节点是fb),现在要合并ab,我们再假设把a的父节点合并到b的父节点上也就是pre[fa] = fb;

根据向量运算fa->fb =  fa->a + a->b +b->fb,这样就能推导出偏移更新式(2-offset[fa] + 1 + offset[b])%2,化简一下就是(1+offset[b]-offset[a]%2ok了,这样就解决掉了。


Find them, Catch them
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 28311   Accepted: 8619

Description

The police office in Tadu City decides to say ends to the chaos, as launch actions to root up the TWO gangs in the city, Gang Dragon and Gang Snake. However, the police first needs to identify which gang a criminal belongs to. The present question is, given two criminals; do they belong to a same clan? You must give your judgment based on incomplete information. (Since the gangsters are always acting secretly.) 

Assume N (N <= 10^5) criminals are currently in Tadu City, numbered from 1 to N. And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. You will be given M (M <= 10^5) messages in sequence, which are in the following two kinds: 

1. D [a] [b] 
where [a] and [b] are the numbers of two criminals, and they belong to different gangs. 

2. A [a] [b] 
where [a] and [b] are the numbers of two criminals. This requires you to decide whether a and b belong to a same gang. 

Input

The first line of the input contains a single integer T (1 <= T <= 20), the number of test cases. Then T cases follow. Each test case begins with a line with two integers N and M, followed by M lines each containing one message as described above.

Output

For each message "A [a] [b]" in each case, your program should give the judgment based on the information got before. The answers might be one of "In the same gang.", "In different gangs." and "Not sure yet."

Sample Input

1
5 5
A 1 2
D 1 2
A 1 2
D 2 4
A 1 4

Sample Output

Not sure yet.
In different gangs.
In the same gang.

Source

POJ Monthly--2004.07.18

#include <cstdio>
#include <cstdlib>

const int MAX = 100002;

int pre[MAX],offset[MAX];

void init(int n){
	int i;

	for(i=1;i<=n;++i){
		pre[i] = i;
		offset[i] = 0;
	}
}

int root(int x){
	int fx;

	if(x!=pre[x]){
		fx = pre[x];
		pre[x] = root(pre[x]);
		offset[x] = (offset[x] + offset[fx])%2;
	}
	return pre[x];
}

void merge(int x,int y){
	int fx = root(x);
	int fy = root(y);

	if(fx!=fy){
		pre[fx] = fy;
		offset[fx] = (1+offset[y]-offset[x])%2;
	}
}

int main(){
	//freopen("in.txt","r",stdin);
	int t,n,m,ra,rb;
	int fa,fb;
	char com;
	scanf("%d",&t);
	while(t--){
		scanf("%d %d%*c",&n,&m);
		init(n);
		while(m--){
			scanf("%c %d %d%*c",&com,&ra,&rb);
			if(com=='D'){
				merge(ra,rb);
			}else{
				fa = root(ra);
				fb = root(rb);
				if(fa != fb){
					printf("Not sure yet.\n");
					continue;
				}
				if(offset[ra] != offset[rb]){
					printf("In different gangs.\n");
					continue;
				}
				printf("In the same gang.\n");
			}
		}
	}
	return 0;
}


你可能感兴趣的:(poj,并查集,1703,偏移向量)