题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数 N,MN,M ,表示共有 NN 个元素和 MM 个操作。
接下来 MM 行,每行包含三个整数 Z_i,X_i,Y_iZi,Xi,Yi 。
当 Z_i=1Zi=1 时,将 X_iXi 与 Y_iYi 所在的集合合并。
当 Z_i=2Zi=2 时,输出 X_iXi 与 Y_iYi 是否在同一集合内,是的输出
Y
;否则输出N
。输出格式
对于每一个 Z_i=2Zi=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
说明/提示
对于 30\%30% 的数据,N \le 10N≤10,M \le 20M≤20 。
对于 70\%70% 的数据,N \le 100N≤100,M \le 10^3M≤103 。
对于 100\%100% 的数据,1\le N \le 10^41≤N≤104,1\le M \le 2\times 10^51≤M≤2×105 。
代码一:
用循环来实现并查集
#include<cstdio>
#include<algorithm>
int n , m ;//n个元素 、 m个操作
int pre[100000] ; //用来记录祖先
//用来寻找祖先
int find1(int x)
{
while(x!=pre[x])
{
x = pre[x] ;
}
return x;
}
int main()
{
scanf("%d %d",&n,&m) ;
//初始化pre数组
for(int i =1 ; i<=n ; i++)
{
pre[i] = i ; //初始化其祖先在一开始的时候是其本身
}
while(m--)
{
int op ; //用来表示操作
int x, y;
scanf("%d %d %d",&op,&x,&y) ;
int a , b ; //用来记录x、y的祖先
a = find1(x) ;
b = find1(y) ;
if(op == 1)
{
pre[a] = b;
}
else if(op == 2)
{
if(a == b)
{
printf("Y\n") ;
}
else printf("N\n") ;
}
}
return 0 ;
}
但是这道题这样做会报错,原因是没有压缩路径。
按照上面代码就会出现上面的这种情况,全部的结点在一条链上,会导致深度变大,查找时耗时更大。
代码二:
#include<cstdio>
#include<algorithm>
int n , m ;//n个元素 、 m个操作
int pre[100000] ; //用来记录祖先
//用来寻找祖先
int find1(int x)
{
while(x!=pre[x])
{
x = pre[x] = pre[pre[x]] ;
}
return x;
}
int main()
{
scanf("%d %d",&n,&m) ;
//初始化pre数组
for(int i =1 ; i<=n ; i++)
{
pre[i] = i ; //初始化其祖先在一开始的时候是其本身
}
while(m--)
{
int op ; //用来表示操作
int x, y;
scanf("%d %d %d",&op,&x,&y) ;
int a , b ; //用来记录x、y的祖先
a = find1(x) ;
b = find1(y) ;
if(op == 1)
{
pre[a] = b;
}
else if(op == 2)
{
if(a == b)
{
printf("Y\n") ;
}
else printf("N\n") ;
}
}
return 0 ;
}
压缩完路径后:
这个代码就避免了上面的那个问题。
代码三:
利用递归来实现并查集
#include<cstdio>
#include<algorithm>
int n , m ;//n个元素 、 m个操作
int pre[100000] ;
//用来寻找祖先
int find1(int x)
{
if(x == pre[x])
return x;
else return pre[x] = find1(pre[x]) ;
}
int main()
{
scanf("%d %d",&n,&m) ;
//初始化pre数组
for(int i =1 ; i<=n ; i++)
{
pre[i] = i ; //初始化其祖先在一开始的时候是其本身
}
while(m--)
{
int op ; //用来表示操作
int x, y;
scanf("%d %d %d",&op,&x,&y) ;
int a , b ; //用来记录x、y的祖先
a = find1(x) ;
b = find1(y) ;
if(op == 1)
{
pre[a] = b;
}
else if(op == 2)
{
if(a == b)
{
printf("Y\n") ;
}
else printf("N\n") ;
}
}
return 0 ;
}