题目链接click here!
题目意思:有n个带序号的石子实现下面两种操作:
1.M 含x的一堆石子整体移动到包含y石子的一堆上面
2.C 输出序号为x的石子下面有多少个石子
模板题稍微改动一下有一篇讲解click here!
1.创建结构体,保存父亲(路径压缩的时候会直接指向根节点)和到根节点的距离(所以不能用一位数组实现)
2.将两个集合合并的时候将含x堆的根节点的距离值更新为含y堆的根节点的父亲取负(代表此集合元素个数取负),父亲更新为y
Here comes the code.
#include<cstdio>
using namespace std;
struct node{
int fa,d;
}dsu[30005];
node Find(int x){
node no;
if(dsu[x].fa<0){
no.fa=x;
no.d=0;
return no;
}//若直接返回 return node{x,0};会出现编译错误,所以还是谨慎起见
no=Find(dsu[x].fa);
no.d+=dsu[x].d;
dsu[x]=no;
return no;
}
void Union(int x,int y){
x=Find(x).fa;
y=Find(y).fa;
if(x==y) return;
dsu[x].d=-dsu[y].fa;
dsu[y].fa+=dsu[x].fa;
dsu[x].fa=y;
}
int p;//也可以定义在main函数里
int main(){
int x,y;
char a;
for(int i=1;i<30004;i++){
dsu[i].fa=-1;//起初都是-1
dsu[i].d=0;
}
scanf("%d",&p);
for(int i=1;i<=p;i++){
scanf("%s",&a);
if(a=='M'){
scanf("%d%d",&x,&y);
Union(x,y);
}
else{
scanf("%d",&x);
printf("%d\n",Find(x).d);
}
}
return 0;
}
attention!!!
那个p在自己电脑上如果定义在main函数里输入只能读入两行。也不知道为啥<( ̄ ﹌  ̄)> 。按照我的理解,应该是可以的,因为p这个变量只在main函数里用到过。回头看看书吧。。。(不过找了半天错真的很让人崩溃啊啊啊)
并查集模板
int Find(int x){
if(dsu[x]<0) return x;
return dsu[x]=Find(dsu[x]);//路径压缩
}
void Union(int x,int y){
x=Find(x);//先用根节点覆盖x,y
y=Find(y);
if(x==y) return;//判断是否在一个集合
dsu[x]+=dsu[y];//x为新集合的根节点,跟新集合元素个数
dsu[y]=x;//更新y的父亲,以前在y集合的点也可以通过y找到x
}