相比无限种类并查集我更认为这题是加权并查集(好吧种类并查集就是加权的一种,不要吐槽了~),这题也是我刷并查集专题的结束。以后博客如果再更并查集就是并查集的难题了233~不过希望我能解出并查集的难题并整理出题解分享给大家。。。
题意:就是说两个农民A和B,面前有n(1<=n<=30000)个相同木块(每个木块都都序号1~n),移动p次(1<=p<=10,000)(次数比较多,我因为这个写的另外两个算法超时了),A让B移动木块。有两种操作
M x y 将包换 x的木块移动到包含y的木块上面。
C x 计算编号是x的 木块下面有多少个木块
思路: 并查集,把放在最下面的一个木块认为是根节点,然后其他放在上面的都用gp标记一下,表示下面有多少个木块(gp[i]表示的是编号是i的木块下面有多少个木块),根节点的gp为0,如果两棵树合并就用find的状态压缩,先递归,再维护(这个在前面几个并查集里详细讲了~),再用a数组存放这个以i为根节点是树中下一个叶子下面有多少个木块,a数组初始化为什么为1比较方便,可以模拟体会一下~
#include<cstdio>
#include<cstring>
#define LOCAL
using namespace std;
int gp[30100],pa[30100],max,min,a[30100];
inline void init(){
for(int i = 0; i < 30050; i++){
pa[i] = i;
gp[i] = 0;
a[i] = 1;
}
}
int find(int x){
int fa;
if(x != pa[x]){
int tmp = pa[x];
pa[x] = find(pa[x]);
gp[x] = gp[tmp] + gp[x];//维护树,加权并查集的写发
}
return pa[x];
}
void unite(int x,int y){
int fx = find(x);
int fy = find(y);
if(fx != fy){
pa[fx] = fy;
gp[fx] = a[fy];
a[fy] += a[fx];
}
}
int main(){
/*#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif*/
int p,x,y;
char c;
scanf("%d",&p);
init();
max = -1;
min = 10010;
while(p--){
getchar();
scanf("%c",&c);
if(c=='C') {
scanf("%d",&x);
find(x);
printf("%d\n",gp[x]);
}
else if(c=='M'){
scanf("%d%d",&x,&y);
unite(x,y);
}
}
return 0;
}