【题目链接】:Click here~~
【题意】:
给 n 块砖头,开始各为一堆,两种操作:
1、把 X 所在的那一堆箱子里的砖头放到 Y 所在的那一堆上面。
2、询问 X 下面有多少块砖。
【解题思路】:好像大家都叫它带权并查集,那为了方便,这里也这样叫吧,因为涉及前面的和后面的箱子个数,对应的查找操作,一开始想用结构体来写,在结构体里定义每个箱子的前驱和后继,每次输入的时候统计一下相应的前驱和后继的个数,后来发现不行,因为涉及到合并操作,比如说M 2 4 M 2 6连续出现两个2,用结构体是不容易实现的,这时候发挥并查集的效果了,在合并的时候分别更新 (1)Sum[i]=1;//i所在的箱子总数,(2)upsum[i]=0;//i下面箱子数,最后C a时直接输出upsum[a]
代码:
/*
Author:HRW
带权并查集
*/
#include <bits/stdc++.h>
using namespace std;
const int N=30005;
int father[N],Sum[N],upsum[N],n,m,a,b,T;
char ch[4];
int find(int x){
if(x!=father[x]){
int temp=find(father[x]);
upsum[x]+=upsum[father[x]];
father[x]=temp;
}
return father[x];
}
void Union(int a,int b)
{
int pa=find(a);
int pb=find(b);
if(pa!=pb){
upsum[pa]=Sum[pb];//合并pa下面pb的所有箱子
Sum[pb]+=Sum[pa];//pb所在的堆的箱子总数
father[pa]=pb;//合并根节点
}
}
void init(){
for(int i=0; i<N; i++)
{
father[i]=i;
Sum[i]=1;//i所在的箱子总数
upsum[i]=0;//i下面箱子数
}
}
int main()
{
while(scanf("%d",&T)!=EOF){
init();
for(int i=0; i<T; i++){
scanf("%s",ch);
if(ch[0]=='M'){
scanf("%d%d",&a,&b);
Union(a,b);
}
else{
scanf("%d",&a);
find(a);
printf("%d\n",upsum[a]);
}
}
}
return 0;
}HDU 2818 Building Block(带权并查集)
原文:http://blog.csdn.net/u013050857/article/details/45243977