Luogu P3367 【模板】并查集 题解

Luogu P3367 【模板】并查集 题解

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入输出格式

输入格式:

第一行包含两个整数N、M,表示共有N个元素和M个操作。

接下来M行,每行包含三个整数Zi、Xi、Yi

当Zi=1时,将Xi与Yi所在的集合合并

当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N

输出格式:

如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N

输入输出样例

输入样例#1:

1
2
3
4
5
6
7
8
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4

输出样例#1:

1
2
3
4
N
Y
N
Y

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据,N<=10,M<=20;

对于70%的数据,N<=100,M<=1000;

对于100%的数据,N<=10000,M<=200000。

从100%数据的范围来看,显然不可能暴搜。所以为解决此题,我们采用基于树的数据结构——并查集。

基本并查集应该提供两个操作:查询(最大祖先)操作和合并操作。

详情见代码注释。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,f[10010];
int find(int x)
{
if(x==f[x]) return x;//边界
return f[x]=find(f[x]);//递归查找结点x的最大祖先y,同时通过路径压缩令x与y之间的所有结点,最大祖先都置为y
}
inline void join(int x,int y)
{
f[x]=y;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) f[i]=i;//初始化令所有结点的最大祖先都是自己
while(m--)
{
int x,y,z,tx,ty;
scanf("%d %d %d",&z,&x,&y);
ty=find(y);//寻找y的最大祖先ty
tx=find(x);//寻找x的最大祖先tx
if(z==1) join(tx,ty);//现在tx是ty家里的人了
else
{
if(tx==ty) printf("Y\n");//如果是同一家的
else printf("N\n");
}
}
return 0;
}
--It's the end.Thanks for your read.--