并查集题目(路径压缩、扩展域并查集、带权并查集、二维转一维并查集、逆向思维并查集)

本文通过多个编程竞赛题目,展示了并查集在处理各种问题中的应用,如家谱构建、程序分析、棋盘游戏、数组修改等,同时结合了哈希表和路径压缩等技巧,深入探讨了并查集的实现策略。

目录

P2814 家谱

P1955 [NOI2015] 程序自动分析

P2256 一中校运会之百米跑    (并查集结合map)

P3144 [USACO16OPEN]Closing the Farm S

P6121 [USACO16OPEN]Closing the Farm G

P1197 [JSOI2008] 星球大战

P5092 [USACO04OPEN]Cube Stacking (带权并查集)

P5877 棋盘游戏

 P8686 [蓝桥杯 2019 省 A] 修改数组

P1840 Color the Axis

P1621 集合  并查集和质数筛结合的一道数学题

Supermarket

P2835 刻录光盘

P1333 瑞瑞的木棍

P2391 白雪皑皑

P2949 [USACO09OPEN]Work Scheduling G

P3402 可持久化并查集


P2814 家谱

#include <bits/stdc++.h>
using namespace std;
int len, cnt, father, fa[50010];
string s;
map<string, int> m;
string a[50010];
int find(int x)
{
	if(fa[x]==x){
		return x;
	}
	else return fa[x]=find(fa[x]);
}
int main()
{
	while(cin>>s && s[0]!='$'){
		string name="";
		len=s.length();
		for(int i=1; i<len; ++i){
			name+=s[i];
		}
		if(s[0]=='#'){
			if(m.count(name)!=0){
				father=m[name];
				continue;
			}
			cnt++;
			m[name]=cnt;
			a[cnt]=name;
			fa[cnt]=cnt;
			father=cnt;
		}
		else if(s[0]=='+'){
			if(m.count(name)!=0){
				int id=m[name];
				fa[id]=father;
				continue;
			}
			cnt++;
			m[name]=cnt;
			a[cnt]=name;
			fa[cnt]=father;
		}
		else if(s[0]=='?'){
			int id=m[name];
			cout << name << " " << a[find(id)] << endl;
		}
	}
	return 0;
}

P1955 [NOI2015] 程序自动分析

并查集和map(哈希)结合起来的一道好题

#include <bits/stdc++.h>
using namespace std;
int t, n, fa[1000010], cnt;
bool flag;
map<int, int> m;
struct node
{
	int x, y, z;
}limit[1000010];
bool cmp(node a, node b)
{
	return a.z>b.z;
}
int find(int x)
{
	if(fa[x]==x){
		return x;
	}
	return fa[x]=find(fa[x]);
}
void merge(int u, int v)
{
	int fu=find(u);
	int fv=find(v);
	if(fu!=fv){
		fa[fu]=fv;
	}
}
int main()
{
	scanf("%d", &t);
	while(t--){		//10
		scanf("%d", &n);
		m.clear();
		flag=true;
		for(int i=1; i<=n; ++i){		//1e6
			scanf("%d %d %d", &limit[i].x, &limit[i].y, &limit[i].z);
		}
		sort(limit+1, limit+n+1, cmp);	//1e6*20 
		for(int i=1; i<=n; ++i){		//1e6 
			int u=limit[i].x;
			int v=limit[i].y;
			int e=limit[i].z;
			if(m.count(u)==0){
				cnt++;
				fa[cnt]=cnt;	//初始化并查集	
				m[u]=cnt;		//将大范围的整数u映射成小范围的整数cnt 
			}
			if(m.count(v)==0){
				cnt++;
				fa[cnt]=cnt;	//初始化并查集
				m[v]=cnt;		//将大范围的整数v映射成小范围的整数cnt 
			}
			if(e==1){			//合并 
				merge(m[u], m[v]);
			} 
			else{				//判断u和v的祖先是否相同 
				int fu=find(m[u]);
				int fv=find(m[v]);
				if(fu==fv){
					flag=false;
					printf("NO\n");
					break;
				}
			}
		}
		if(flag){
			printf("YES\n");	
		}
	}
	return 0;
}

P2256 一中校运会之百米跑    (并查集结合map)

#include <bits/stdc++.h>
using namespace std;
const int N=20010; 
int n, m, k, fa[N], u, v, fu, fv;
string name1, name2;
map<string, int> asd;
int find(int x)
{
	if(fa[x]==x){
		return x;
	}
	else{
		return fa[x]=find(fa[x]);
	}
}
void merge(int u, int v)
{
	int fu=find(u);
	int fv=find(v);
	fa[fu]=fv;
}
int main()
{
	scanf("%d %d", &n, &m);
	for(int i=1; i<=n; ++i){
		fa[i]=i;
		cin >> name1;
		asd[name1]=i;
	}
	while(m--){
		cin >> name1 >> name2;
		u=asd[name1];
		v=asd[name2];
		merge(u, v);
	}
	scanf("%d", &k);
	while(k--){
		cin >> name1 >> name2;
		u=asd[name1];
		v=asd[name2];
		if(find(u)==find(v)){
			printf("Yes.\n");
		}
		else{
			printf("No.\n");
		}
	}
	return 0;
}

P3144 [USACO16OPEN]Closing the Farm S

并查集倒着做合并, AC

#include <bits/stdc++.h>
using namespace std;
int
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ypeijasd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值