您的位置:首页 > 产品设计 > UI/UE

HDU 2818 Building Block 带权并查集

2014-04-19 21:21 489 查看
题目链接:http://acm.hdu.edu.cn/status.php

转载请注明出处:http://blog.csdn.net/u012860063

/*挺不错的一道题目,并查集的确是最优美的数据结构之一。

题目大意:有N个piles(按序编号),每次有两种操作:

M x y表示把x所在的那一堆全部移到y所在的那一堆

C x 询问在x之下有多少个方块

解决方法:使用并查集(路径压缩)实现,

然后用num[X]表示X所在的那一堆总共多少个piles,under[x]表示x之下有多少个piles。

首先,每次操作我们合并两个集合(如果原来在同一集合中除外),

num[X]是每次操作可以直接实现的,就是把两堆的数目相加,很容易(初始值为1)。

那么当某次移动操作发生时,首先确定x所在的那一堆最底部的X以及y所在那一堆最底部的Y,

那么under[X]的数目就是另外一堆piles的总数num[Y],有了这个条件,在接下去的操作中,

就可以根据find(x)递归去一边寻找根一边更新其他未知的under[x],。

*/

#include<cstdio>
#include<cstring>
int num[333333];//num[X]:X是集合代表,某个堆(集合)中Piles的总数
int father[333333];
int under[333333];//under[i]: 编号为i的Pile下面有多少个Piles (一边进行查找,一边更新)
int find(int x)
{
    int tmp;
    if (x!=father[x])
    {
        tmp = find(father[x]);
        under[x] += under[father[x]];
		//递归过程自底向上自动更新under[],递归基础:下面的under[X] = num[Y]
        father[x] = tmp;
    }
    return father[x];
	
}
void merge(int a,int b)
{
    int X=find(a);
    int Y=find(b);
    if(X!=Y)
    {
        under[X]=num[Y];//X是当前堆(集合)中最底部的,直接更新under[]
        num[Y]+=num[X]; //直接更新Y这堆(集合)的高度(总共多少个Piles)
        father[X]=Y; //合并,注意是X加到Y上,不同于一般的并查集的father[Y]=X
    }
}
int main()
{
    int n,a,b,i;
    char s[5];
    while(scanf("%d",&n)!=EOF)
    {
        memset(under,0,sizeof(under));
        for(i=0; i<=n; i++)//初始化
        {
            father[i]=i;
            num[i]=1;
        }
        for(i=0; i<n; i++)
        {
            scanf("%s",s);
            if(s[0]=='M')
            {
                scanf("%d%d",&a,&b);
                merge(a,b);
            }
            else
            {
                scanf("%d",&a);
                find(a);
                printf("%d\n",under[a]);
            }
        }
    }
    return 0;
} 
/*
6
M 1 6
C 1
M 2 4
M 2 6
C 3
C 4
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: