原题链接
P3367
题目类型:
普
及
−
{\color{orange} 普及-}
普及−
题目大意
给你
n
n
n个元素和
m
m
m次操作,初始时每一个元素自己就是一个集合,每一次操作都会给你三个数
z
i
,
x
i
,
y
i
z_i,x_i,y_i
zi,xi,yi,当
z
i
z_i
zi为
1
1
1时,合并
x
i
x_i
xi和
y
i
y_{i}
yi所在的集合,当
z
i
z_i
zi为
2
2
2时查询
x
i
x_i
xi和
y
i
y_i
yi是否在同一个集合里,是就输出Y
,否则输出N
。
S
a
m
p
l
e
\mathbf{Sample}
Sample
I
n
p
u
t
\mathbf{Input}
Input
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
S a m p l e \mathbf{Sample} Sample O u t p u t \mathbf{Output} Output
N
Y
N
Y
H
i
n
t
&
E
x
p
l
a
i
n
\mathbf{Hint\&Explain}
Hint&Explain
原来的集合是这样的:{1},{2},{3},{4}
执行第二条语句后是这样的:{1,2},{3},{4}
执行第四条语句后是这样的:{1,2},{3,4}
执行第六条语句后是这样的:{1,2,3,4}
输出部分就自己看啦 主要是作者懒得打
数据范围
对于
30
%
30\%
30%的数据,
N
≤
10
,
M
≤
20
N\le 10,M\le 20
N≤10,M≤20。
对于
70
%
70\%
70%的数据,
N
≤
100
,
M
≤
1
0
3
N\le 100,M\le 10^3
N≤100,M≤103。
对于
100
%
100\%
100%的数据,
1
≤
N
≤
1
0
4
,
1
≤
M
≤
2
×
1
0
5
,
1
≤
X
i
,
Y
i
≤
N
,
Z
i
∈
{
1
,
2
}
1\le N\le 10^4,1\le M\le 2\times10^5,1\le X_i,Y_i \le N,Z_i\in \{1,2\}
1≤N≤104,1≤M≤2×105,1≤Xi,Yi≤N,Zi∈{1,2}。
解题思路
这是一道并查集模板题,对于并查集,我们需要实现两个操作,一个是查询该元素在哪个集合里面,一个是合并集合。我们不妨设他为find
函数和merge
函数。
先看find
函数,我们可以将每一个集合都拿出一个元素作为集合代表元素,用
f
a
i
fa_i
fai记录
i
i
i所在的集合的集合代表元素,当然集合代表元素的
f
a
fa
fa,就是他本身。我们可以通过递归来实现find
函数,就是找出集合代表元素,同时也可以顺便标记一下他名下的元素的
f
a
fa
fa。
int find(int x)
{
if(fa[x]==x)
return x;
return (fa[x]=find(fa[x]));
}
再看merge
函数,把两个集合合并,就是把他们的集合代表元素变成一个,只需要找出两个元素所在集合的代表元素,使其变成一个,就可以合并了。
void merge(int x,int y)
{
x=find(x),y=find(y);
if(x==y)
return;
fa[x]=y;
}
其他的也不多说了,就是一道模板题,只要掌握了并查集的两种基本操作,就可以按题目做出来了。
上代码
#include<iostream>
using namespace std;
int fa[10010];
int find(int x)
{
if(fa[x]==x)
return x;
return (fa[x]=find(fa[x]));
}
void merge(int x,int y)
{
x=find(x),y=find(y);
if(x==y)
return;
fa[x]=y;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++)
fa[i]=i;
while(m--)
{
int x,y,z;
cin>>z>>x>>y;
if(z==1)
merge(x,y);
else
{
x=find(x),y=find(y);
if(x==y) cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
}
return 0;
}
int main()
{
int t; cin>>t;
while(t--){work();}
return 0;
}
完美切题 ∼ \sim ∼