并查集的两个操作
1、将两个集合合并
2、询问两个元素是否在一个集合当中
https://www.luogu.com.cn/problem/P3367
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
其中最重要的是find函数,是返回x的祖宗节点,加了路径压缩,使得每一个数指向的都是祖宗节点,在后期的查找中只要找一次就能找到。p[x]存储的是父节点,当p[x]=x时是根节点,return p[x]。
输入样例:
4 7 2 1 2 1 1 2 2 1 2 1 3 4 2 1 4 1 2 3 2 1 4
代码:
int s,a,b;
cin>>s>>a>>b;
if(s==1) p[find(a)]=find(b);
else if(s==2) {
if(find(a)==find(b))cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
当s==2时,执行第二个操作,询问两个元素是否在一个合集内:此时p[1]=1,p[2]=2,find(1)=1,find(2)=2,所以两个元素的祖宗节点不同,因此不在一个集合内,输出“N”;
当s==1时,执行第一个操作,合并两个集合:找出2的祖宗节点赋值给p[1],完成将1插入2的集合的操作,使得在查找时1和2的祖宗节点是一样的;
再一次当s==2时,执行第二个操作,询问两个元素是否在一个合集内:此时find[1]=find[2],输出“Y”;
输出样例:
N Y N Y
完整代码:
#include<iostream>
using namespace std;
const int N=2e5+10;
int p[N];
int find(int x) {
if(p[x]!=x) p[x]=find(p[x]);//如果x指向它本身,说明它就是祖宗节点,return p[x];如果不是,就寻找此集合的祖宗节点并赋值给p[x]
return p[x];
}
int main() {
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++) {
p[i]=i;
}
while(m--) {
int s,a,b;
cin>>s>>a>>b;
if(s==1) p[find(a)]=find(b);//实现合并集合,将a插入到b中,将a指向b的祖宗节点
else if(s==2) {
if(find(a)==find(b))cout<<"Y"<<endl;//比较两个元素的祖宗节点是否一致
else cout<<"N"<<endl;
}
}
return 0;
}