Hduoj2818【带权并查集】

/*Building Block
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3894    Accepted Submission(s): 1209


Problem Description
John are playing with blocks. There are N blocks (1 <= N <= 30000) numbered 1...N。Initially, there are N piles, and each pile 
contains one block. Then John do some operations P times (1 <= P <= 1000000). There are two kinds of operation:

M X Y : Put the whole pile containing block X up to the pile containing Y. If X and Y are in the same pile, just ignore this command. 
C X : Count the number of blocks under block X 

You are request to find out the output for each C operation.

Input
The first line contains integer P. Then P lines follow, each of which contain an operation describe above.

Output
Output the count for each C operations in one line.

Sample Input
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4

Sample Output
1
0
2

Source
2009 Multi-University Training Contest 1 - Host by TJU 

Recommend
gaojie   |   We have carefully selected several similar problems for you:  2819 2824 2821 2820 2822 
*/ 
#include<stdio.h>
#include<string.h>
int f[30010], down[30010], up[30010];
int find(int x)
{
	if(x == f[x])
	return x;
	int temp = find(f[x]);//先要更新其父节点到最底部的值 
	down[x] += down[f[x]];//当前点到其最底部的值加上其父节点到最底部的值 
	f[x] = temp;//更新完毕后要更新当前点的父节点~即更新当前点的最底部的点 
	return f[x];
}

void update(int x, int y)
{
	int i, max = 0;
	x = find(x);
	y = find(y);
	if(x == y)
	return ;
	down[x] = up[y];//将x到y堆的最底部的值更新为y到其自身的最顶部的值 
	up[y] += up[x];//再更新y堆到最顶部 的值 
	f[x] = y;//合并2堆 
}
int main()
{
	int i, j, k,p;
	scanf("%d", &p);
	for(i = 0; i <= 30000; ++i)
	{
		f[i] = i;
		up[i] = 1;//假设存在一个顶部,则到顶部的距离初始化为1 
					//更新的时候即代表新的顶部到最底部的距离 
	}
	while(p--)
	{
		getchar();
		char ch;
		scanf("%c", &ch);
		if(ch == 'C')
		{
			scanf("%d", &k);
			find(k);//计算k到最底部的值 
			printf("%d\n", down[k]); 
		} 
		else
		{
			int a, b;
			scanf("%d %d", &a, &b);
			update(a, b);
		}
	}
	return 0;
}


题意:有n堆积木,刚开始每堆积木都只有一个积木,现在对其进行2中操作,第一种是M X Y 表示将包含X积木的那一堆放在包含Y积木的那一堆上面,如果X和Y属于同一堆则无视该操作。第二种就是C X 表示查询X积木下面有多少个积木。

思路:这道题有点难想,也许可以从X和Y属于同一堆的话则取消该操作 想到并查集,但是却不知道该怎么用并查集去解决这道题,首先考虑2堆积木,每堆积木的个数未知,我们可以将最底部的积木作为根节点,用up和down数组分别表示当前积木到该堆的顶部的距离和底部的距离,每当2堆积木进行合并操作的时候,我们将X堆放在上面,则相当于X到底部的距离变成了Y到顶部的距离,接着Y到顶部的距离要加上X到顶部的距离。这样2堆就合并完成了,而当要求积木到最底部的距离时,就得进行路径压缩,一边压缩,一边进行求和,就是求父节点到最底部的距离加上当前点到父节点的距离,因为对于每一个父节点来说它就是最底部的那个积木,所以一直搜索到最终的那个积木再进行回溯就可以求出当前积木到最底部的距离,同时也将每个积木的父节点全部更新了一遍。

难点:在于建立数据模型和并查集之间的联系。

你可能感兴趣的:(Hduoj2818【带权并查集】)