并查集专题

并查集是可以用来处理类似家谱的需要快速合并与查找祖先的一种集合性质的数据结构

并查集模板

// size:大小 compress:路径压缩 merge_rank:按秩合并 
template<int size=2500,bool compress=true,bool merge_rank=true>
class UnionFindSet{
	private:
		int fa[size+1];
		int rank[size+1];
	public:
		UnionFindSet(){
			for(int i=0;i<size;i++){
				this->fa[i]=i;
				if(merge_rank){
					this->rank[i]=1;
				} 
			}
		}
		int find(int x){
			if(!compress){
				if(this->fa[x]==x){
					return x;
				}
				else{
					return this->find(this->fa[x]);
				}
			}
			else{
				if(x==this->fa[x]){
					return x;
				}
				else{
					this->fa[x]=this->find(this->fa[x]);
					return fa[x];
				}
			}
		}
		void merge(int x,int y){
			if(!merge_rank){
				this->fa[this->find(x)]=find(y);
			}
			else{
				int a=this->find(x);
				int b=this->find(y);
				if(this->rank[a]<=this->rank[b]){
					this->fa[a]=b;
				}
				else{
					this->fa[b]=a;
				}
				if(rank[a]==rank[b]&&a!=b){
					rank[b]++;
				}
			}
		}
		bool same(int x,int y){
			return this->find(x)==this->find(y);
		}
		void _fa_setValue(int i,int x){
			this->fa[i]=x;
		}
		int _fa_getValue(int i){
			return this->fa[i]; 
		}
		void _rank_setValue(int i,int x){
			this->rank[i]=x;
		}
		int _rank_getValue(int i){
			return this->rank[i];
		}
};

PS:以下代码均省略模板!

例题

P3367 【模板】并查集

P3367 【模板】并查集

模板题,套模板即可。

#include<bits/stdc++.h>
using namespace std;

UnionFindSet<10010,true,true> ufs;
int n,m;

int main(){
	cin>>n>>m;
	while(m--){
		int z,x,y;
		cin>>z>>x>>y;
		switch(z){
			case 1:
				ufs.merge(x,y);
				break;
			default:
				if(ufs.same(x,y)){
					cout<<'Y'<<endl;
				}
				else{
					cout<<'N'<<endl;
				}
		}
	}
	return 0;
}

P1551 亲戚

P1551 亲戚

近似于模板题。

#include<bits/stdc++.h>
using namespace std;

UnionFindSet<10010,true,true> ufs;
int n,m,p;

int main(){
	cin>>n>>m>>p;
	for(int i=1;i<=m;i++){
		int mi,mj;
		cin>>mi>>mj;
		ufs.merge(mi,mj);
	} 
	while(p--){
		int pi,pj;
		cin>>pi>>pj;
		if(ufs.same(pi,pj)){
			cout<<"Yes"<<endl;
		}
		else{
			cout<<"No"<<endl;
		}
	}
	return 0;
}

P2256 一中校运会之百米跑

P2256 一中校运会之百米跑

这道题关键在于使用std::map容器进行字符串与int的映射。

#include<bits/stdc++.h>
using namespace std;

UnionFindSet<20005,true,true> ufs;
map<string,int> ma;

int n,m,k;

int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		string str;
		cin>>str;
		ma[str]=i;
	}
	for(int i=1;i<=m;i++){
		string a,b;
		cin>>a>>b;
		ufs.merge(ma[a],ma[b]);
	}
	cin>>k;
	while(k--){
		string s1,s2;
		cin>>s1>>s2;
		if(ufs.same(ma[s1],ma[s2])){
			cout<<"Yes.\n";
		}
		else{
			cout<<"No.\n";
		}
	}
	return 0;
}

P1682 过家家

P1682 过家家

其实这道题只要看懂题意,并且能够与图论结合,就很水了。

#include<bits/stdc++.h>
using namespace std;

UnionFindSet<100005,true,true> ufs;
int n,m,k,f;

struct Edge{
	int from;int to;
} edge1[100005],edge2[100005];
bool lt[505][505];int countable[100005];
int ans=INT_MAX;

int main(){
	cin>>n>>m>>k>>f;
	for(int i=1;i<=m;i++){
		cin>>edge1[i].from>>edge1[i].to;
	}
	for(int i=1;i<=f;i++){
		cin>>edge2[i].from>>edge2[i].to;
	}
	for(int i=1;i<=f;i++){
		ufs.merge(edge2[i].from,edge2[i].to);
	}
	for(int i=1;i<=m;i++){
		if(!lt[ufs.find(edge1[i].from)][edge1[i].to]){
			countable[ufs.find(edge1[i].from)]++;
			lt[ufs.find(edge1[i].from)][edge1[i].to]=true;
		;}
	}
	for(int i=1;i<=n;i++){
		if(countable[i]){
			ans=min(ans,countable[i]);
		}
	}
	ans=min(ans+k,n); 
	printf("%d",ans);
	return 0;
}
posted @ 2022-01-26 15:27  蒟蒻xiezheyuan  阅读(26)  评论(0编辑  收藏  举报