并查集(Union Find)
准备工作
可以先看这个 超有爱的并查集~
解释的非常生动形象 tql
正文
oj用的是洛谷 P3367 【模板】并查集
优化有两种方式:
- 路径压缩(常用)
- 按秩合并
路径压缩
#include <bits/stdc++.h>
using namespace std;
int n,m;
int pre[10005]; //父节点
int find(int r){
if(r==pre[r]) return r; //根节点的pre是自己
return pre[r]=find(pre[r]); //①路径压缩
}
int main(){
cin>>n>>m;
for(int i=0;i<=n;++i) pre[i]=i;
int zi,xi,yi,r1,r2;
while(m--){
cin>>zi>>xi>>yi;
r1=find(xi);
r2=find(yi);
if(zi==1){ //普通合并
if(r1!=r2) pre[r1]=r2; //xi所在的树合并到yi所在树
}
else{ //判断是否在一个并查集
if(r1!=r2) cout<<"N
";
else cout<<"Y
";
}
}
return 0;
}
按秩合并
#include <bits/stdc++.h>
using namespace std;
int n,m;
int pre[10005]; //父节点
int ran[10005]; //秩(树高)
int find(int r){
if(r==pre[r]) return r;
return pre[r]=find(pre[r]); //①路径压缩
}
int main(){
cin>>n>>m;
for(int i=0;i<=n;++i) {pre[i]=i; ran[i]=1;}
int zi,xi,yi,r1,r2;
while(m--){
cin>>zi>>xi>>yi;
r1=find(xi);
r2=find(yi);
if(zi==1){ //②按秩合并
if(r1!=r2){ //将高度小的树合并到高度大的树上
if(ran[r1]<ran[r2]) //r1->r2
pre[r1]=r2;
else{ //r2->r1
if(ran[r1]==ran[r2]) ++ran[r1]; //相等合并时树高+1
pre[r2]=r1;
}
}
}
else{
if(r1!=r2) cout<<"N
";
else cout<<"Y
";
}
}
return 0;
}