题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入输出格式
输入格式:
第一行包含两个整数N、M,表示共有N个元素和M个操作。
接下来M行,每行包含三个整数Zi、Xi、Yi
当Zi=1时,将Xi与Yi所在的集合合并
当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N
输出格式:
如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N
输入输出样例
输入样例#1
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
输出样例#1:
N
Y
N
Y
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据,N<=10,M<=20;
对于70%的数据,N<=100,M<=1000;
对于100%的数据,N<=10000,M<=200000。
对于以上这道题,首先我们要知道什么是并查集。并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。那么就涉及到如何并,如何查的问题了。
我们来举个栗子:
a[i]:记录i的祖宗。
father(i):返回i号元素的祖宗。
check(i,j):判断i,j是不是同一个祖宗,是的话返回true,不是返回false。
假如有6个元素,各自为一个集合 | {1},{2},{3},{4},{5},{6} |
---|---|
初始化:假如我们让每个集合内的元素的祖宗都设为它自己 | a[1]=1,a[2]=2…a[6]=6 |
检查:假如我们要将1号元素和2号元素相合并,这时候我们就要判断1号元素和2号元素是不是一个祖宗,如果是,那么他们就已经合并了,如果不是,那么就要开始合并 | if(check(i,j)==true) 已经是同一个集合不用合并; else 进入下一步合并操作 |
合并:我们只要将一方的祖宗设置为另一方的祖宗那么就合并成功了,因为我们在检查是否是一个集合的时候,是通过祖宗是否相等来判断的 | a[father(2)]=father(1) |
那么并查集的大概情况我们就很好理解了。下面我们就来贴上例题的代码:
#include<stdio.h>
int N,M;
int a[10001];
int father(int x)
{
if(a[x]==x)
return x;
a[x]=father(a[x]);//路径压缩,以免我们辛辛苦苦找的下次还要找一次
return father(a[x]);//如果x的祖宗不是它自己,那么它的祖宗就是它祖宗的祖宗
}
bool check(int x,int y)
{
if(father(x)==father(y))
return true;
else return false;
}
void merge(int x,int y)//将元素x和y合并到一个集合
{
if(check(x,y)==false)
a[father(x)]=father(y);//x的祖宗的祖宗=y的祖宗
}
int main()
{
int x,y,z;
scanf("%d %d",&N,&M);
for(int i=1;i<=N;i++)//初始化:每个元素的祖宗都是它本身
a[i]=i;
for(int i=1;i<=M;i++)
{
scanf("%d %d %d",&z,&x,&y);
if(z==1)//合并
merge(x,y);
else if(z==2)//查询是否在同一个集合
{
if(check(x,y))
printf("Y\n");
else printf("N\n");
}
}
}