poj1988

题目链接click here!
题目意思:有n个带序号的石子实现下面两种操作:
1.M 含x的一堆石子整体移动到包含y石子的一堆上面
2.C 输出序号为x的石子下面有多少个石子

模板题稍微改动一下有一篇讲解click here!
1.创建结构体,保存父亲(路径压缩的时候会直接指向根节点)和到根节点的距离(所以不能用一位数组实现)
2.将两个集合合并的时候将含x堆的根节点的距离值更新为含y堆的根节点的父亲取负(代表此集合元素个数取负),父亲更新为y

Here comes the code.

#include
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
}

你可能感兴趣的:(并查集)