【马蹄集】—— 并查集专题

文章提供了几个使用并查集解决实际问题的编程题,包括判断附庸关系、处理蜂蜜值共享、构建暧昧团以及管理通讯簿和一元多项式加法的问题。通过这些例子,展示了并查集在解决关系网络和数据组合问题上的应用。
摘要由CSDN通过智能技术生成

并查集专题






MT2137 附庸的附庸

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

蒙德城的旧贵族们存在着附庸的关系。欧洲有一位伟人说过,我的附庸的附庸不是我的附庸。尽管如此,他们还是存在着隐性的自上而下的关系,属于同一个利益集团。所以,在蒙德城,附庸的附庸也是附庸。也就是说,如果两个附庸都能追溯到同一个贵族,他们也存在附庸关系(仅仅是蒙德人这样认为)蒙德城人口众多,现在小码哥把各人的关系都梳理了出来交给了你,并想让你告诉他,某两个人存不存在附庸关系(按照蒙德人的观念)。

格式

输入格式:第一行一个整数n,表示n个关系;
     接下来 n n n 行,每行两个数 a , b a, b a,b,表示 b b b a a a 的附庸;
     下一行一个整数 q q q,表示询问次数;
     接下来 q q q 行,每行两个数 a , b a,b a,b,询问 a a a b b b 是否存在附庸关系。
输出格式: q q q 行,每行一个数。
      1 1 1 表示存在附庸关系, 0 0 0 表示不存在。

样例 1

输入:5

   1 2
   2 3
   1 7
   4 5
   5 6
   2
   2 7
   1 4

输出:1
   0

备注

其中: 5 ≤ n ≤ 10000 , 2 ≤ q ≤ 2000 , 1 ≤ a , b ≤ 20000 , a ≠ b 5≤n ≤10000,2≤q≤2000,1≤a,b≤20000, a≠b 5n10000,2q2000,1a,b20000,a=b,保证涉及询问的关系中不存在环。


相关知识点: 并查集


题解


本题考察了并查集的使用(有对该数据结构尚不清楚的请移步:【算法与数据结构】 并查集),下面直接给出完整代码(已 AC):

/*
	MT2137 附庸的附庸 
*/ 

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

const int MAX = 1e4+5;
int ary[MAX];

void init(){
	for(int i=0;i<MAX;i++)
		ary[i] = i; 
}

int find(int x){
	return x==ary[x]?x:(ary[x]=find(ary[x]));
}

int main( )
{
	// 录入数据 
	int n, a, b;cin>>n;
	
	// 初始化并查集
	init();
	
	// 建立关系 
	while(n--){
		cin>>a>>b;
		ary[b] = a;
	}
	
	// 开始查询
	cin>>n;
	while(n--){
		cin>>a>>b;
		if(find(a) == find(b)) cout<<"1"<<endl;
		else cout<<"0"<<endl;
	} 
	
    return 0;
}


MT2138 采蜜

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

现在有 n n n 个蜂巢,每一个蜂窝都对应了一个蜂蜜值 s i s_i si
小码哥发现:有一些蜂窝相互联结,使得他们可以共享蜂蜜值,即该蜂巢的蜂蜜值变为:它和它连接(直接连接或间接连接)的蜂巢的蜂蜜值的和。
现在小码哥想要查询一下一些蜂巢的蜂蜜值。

格式

输入格式:第一行有两个数 n n n(蜂巢的数量)、 m m m(操作的数量);
     第二行有 n n n 个数字 ( s 1 , … ⋅ , s n ) (s_1,…· , s_n) (s1⋅,sn)︰分别表示了每一个蜂巢的蜂蜜值;
     随后有m行:第一个数字如果是 1,则后面还有两个数字 a , b a, b a,b,表示此次发现蜂巢 a a a b b b 是相连的。第一个数字如果是 2 2 2,则后面只有一个数字 c c c,表示查询所有与蜂巢 c c c 相连的蜂巢(包括自己)的总蜂蜜值。
输出格式:对每一次的查询操作输出查询的蜂巢的蜂蜜值。

样例1

输入:4 6
   1 1 1 1
   1 1 2
   2 1
   1 2 3
   2 1
   1 3 4
   2 1

输出:2
   3
   4

备注

其中: 1 ≤ m , n ≤ 100000 , 0 ≤ s i ≤ 100 1\le m, n\le 100000,0\le s_i\le100 1m,n100000,0si100


相关知识点:并查集


题解


本题依然考察了并查集的使用,下面直接给出完整代码(已 AC):

/*
	MT2138 采蜜 
	
*/ 

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

const int MAX = 1e5+5;
int ary[MAX], num[MAX];

int find(int x){
	return x==ary[x]?x:(ary[x]=find(ary[x]));
}

void merge(int x, int y){
	x = find(x);
	y = find(y);
	if(x != y){
		ary[x] = y;
		num[y] += num[x];
	}
}

int main( )
{
	// 录入数据 
	int n, m, opt, a, b; 
	cin>>n>>m;
	
	// 初始化
	for(int i=1;i<=n;i++){
		cin>>num[i];
		ary[i] = i; 
	}
	
	// 查询
	while(m--){
		cin>>opt;
		if(opt == 1){
			cin>>a>>b;
			merge(a,b);
		}
		else{
			cin>>a;
			cout<<num[find(a)]<<endl;
		}
	} 
	
    return 0;
}


MT2139 暧昧团

难度:黄金    时间限制:1秒    占用内存:128M
题目描述

小码哥正在整理 NPU 的学生信息。现在到了关键的一步:存储 cp 信息。
因为众所周知情网很乱,所以可能一个人和多个人暧昧,并且不分性别,而且有可能目己和目己暖昧。
同时一对暖昧关系可能会由于大意等原因多次记录。
现在我们知道 n n n 个人,并且有 m m m 个暧昧关系。
现在我们对暧昧团进行定义:一个人所有和他有直接暧昧关系以及间接暧昧关系的集合
比如 1 与 2 暧昧,2 与 3 暧味,3 与 4 暧昧,5 与 3 暧昧,6 与 2 暧味,那么 {1,2,3,4,5,6}, {2,3}, {1,4,5,6}, {空集合} 就均属于暧味团,其中,{1,2,3,4,5,6} 就是极大暧昧团。
现在小码哥告诉你一个人名的编号 a a a ,让你回答与 a a a 所处极大暧昧团的大小。
如果一个人和谁都不暖昧,那么答案就是 1。

格式

输入格式:第一行一个整数 n , m ( 1 ≤ n , m ≤ 1 e 5 ) n,m ( 1≤n,m ≤ 1e5) nm(1nm1e5),表示人数,和暧昧关系的数量;
     接下来m行,每行两个整数 a , b ( 1 ≤ a , b ≤ n ) a,b (1≤a, b≤n) a,b(1abn),表示 a , b a,b ab 之间存在暧昧关系;
最后一行一个整数 x x x,表示询问 x x x 所处极大暧昧团的大小。
输出格式:一行一个整数表示答案。

样例 1

输入:6 8
   1 2
   5 2
   3 6
   4 5
   1 4
   2 2
   3 6
   3 6
   3

输出:2


相关知识点:并查集


题解


依然考察了并查集,下面直接给出求解本题的完整代码(已 AC):

/*
	MT2139 暧昧团 
	
*/ 

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

const int MAX = 1e5+5;
int ary[MAX], num[MAX];

int find(int x){
	return x==ary[x]?x:(ary[x]=find(ary[x]));
}

void merge(int x, int y){
	x = find(x);
	y = find(y);
	if(x != y){
		ary[x] = y;
		num[y] += num[x];
	}
}

int main( )
{
	// 录入数据 
	int n, m, a, b; 
	cin>>n>>m;
	
	// 初始化
	for(int i=1;i<=n;i++){
		ary[i] = i; 
		num[i] = 1;
	}
	
	// 合并
	while(m--){
		cin>>a>>b;
		merge(a,b);
	} 
	
	// 开始查询
	cin>>n;
	cout<<num[find(n)]<<endl;
	
    return 0;
}


MT2132 管理通讯簿

难度:白银    时间限制:1秒    占用内存:128M
题目描述

已知一个通讯记录是由学号(6位整数,并且学号不重复)、姓名(长度小于10,只包含大写字母和小写字母)、性别(F或M)、出生日期(长度小于10)、邮编(6位整数)、通讯地址(长度小于30,只包含大写字母或小写字母)、QQ号(9位整数)、电话(11位整数)等数据项组成,利用单链表编写管理通讯簿(多个通讯记录)的程序,要求实现添加、删除、查找、逆序打印通讯记录功能。输入必须合理。

格式

输入格式:第一行输入学生数量,正整数(大于2,小于10);
     后续行依次输入每个学生学号、姓名、性别、生日、邮编、通讯地址、QQ号、电话,空格分隔。每个学生一行。输入数据必须合理,不考虑不合理的输入或是溢出等特殊情况。然后输入正整数N,根据N的值执行添加、删除、查找、逆序打印。
     如上文所述,首先输入学生信息来建立通讯录。然后输入正整数N:
     如果N为1,执行添加操作,后续行输入一个学生学号、姓名、性别、生日、邮编、通讯地址、QQ号、电话,空格分隔。然后输出第一行The records is:,后续行逆序打印通讯录。
     如果N为2,执行删除操作,第二行输入整型学号,删除对应节点(若找不到要删除的节点,则不进行删除操作),然后输出第一行The records is:,后续行逆序打印通讯录。
     如果N为3,执行查找操作,输入整型学号,如果能够查找到这一条记录则输出查到的记录,找不到则输出not found
     如果N为4,执行逆序打印操作,输出第一行 The records is:,后续行逆序打印通讯录。
输出格式:根据N的值,输出对应的操作结果,如样例所示。

样例 1

输入:4
   202101 Mike F 2017513 710072 xigongda 810794716 18392561229
   202102 Wendy M 2018513 710071 xigongda 123451229 18392561221
   202103 Wesley M 2019513 710012 xigongda 123411189 18392561211
   202106 Wink F 2017212 110072 xigongda 121116710 18392561111
   4

输出:The records is:
   202106 Wink F 2017212 110072 xigongda 121116710 18392561111
   202103 Wesley M 2019513 710012 xigongda 123411189 18392561211
   202102 Wendy M 2018513 710071 xigongda 123451229 18392561221
   202101 Mike F 2017513 710072 xigongda 810794716 18392561229


相关知识点:链表


题解


纯考察链表,下面直接给出求解本题的完整代码(已 AC):

/*
	MT2132 管理通讯簿 
*/ 

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

struct Node{
	int ID,postCode,QNum,next;
	string name,sex,birthday,address,tel;
};

int head, last;
Node nodes[10];

void insert(){
	Node tmp;
	cin>>tmp.ID>>tmp.name>>tmp.sex>>tmp.birthday>>
		tmp.postCode>>tmp.address>>tmp.QNum>>tmp.tel;
	nodes[++last] = tmp;
	nodes[last].next = nodes[head].next;
	nodes[head].next = last;
}

void del(){
	int num; cin>>num;
	int now = head;
	while(nodes[now].next){
		if(nodes[nodes[now].next].ID == num){
			nodes[now].next = nodes[nodes[now].next].next;
			return;
		}
		else now = nodes[now].next;
	}
}

void find(){
	int num; cin>>num;
	int now = nodes[head].next;
	while(now){
		if(nodes[now].ID == num){
			cout<<nodes[now].ID<<" "<<nodes[now].name<<" "
			<<nodes[now].sex<<" "<<nodes[now].birthday<<" "
			<<nodes[now].postCode<<" "<<nodes[now].address<<" "
			<<nodes[now].QNum<<" "<<nodes[now].tel<<endl;
			return;
		}else
			now = nodes[now].next;
	}
	cout<<"not found"<<endl;
}

void print(){
	cout<<"The records is:\n";
	int now = nodes[head].next;
	while(now){
		cout<<nodes[now].ID<<" "<<nodes[now].name<<" "
			<<nodes[now].sex<<" "<<nodes[now].birthday<<" "
			<<nodes[now].postCode<<" "<<nodes[now].address<<" "
			<<nodes[now].QNum<<" "<<nodes[now].tel<<endl;
		now = nodes[now].next;
	}
}

int main( )
{ 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		insert();
	cin>>n;
	switch(n){
		case 1:
			insert();
			print();
			break;
		case 2:
			del();
			print();
			break;
		case 3:
			find();
			break;
		case 4:
			print();
			break;	
	}
    return 0;
}


MT2133 一元多项式的加法

难度:钻石    时间限制:1秒    占用内存:128M
题目描述

小码哥给出两个一元多项式 L A L_A LA L B L_B LB,请你将这两个一元多项式相加,得到新的一元多项式 L C L_C LC
如样例:
L A = 1 − 10 x 6 + 2 x 8 + 7 x 14 L_A=1-10x^6+2x^8+7x^{14} LA=110x6+2x8+7x14
L B = − x 4 + 10 x 6 − 3 x 10 + 8 x 14 + 4 x 18 L_B=-x^4+10x^6-3x^{10}+8x^{14}+4x^{18} LB=x4+10x63x10+8x14+4x18
L C = L A + L B = 1 − x 4 + 2 x 8 − 3 x 10 + 15 x 14 + 4 x 18 L_C=L_A+L_B=1-x^4+2x^8-3x^{10}+15x^{14}+4x^{18} LC=LA+LB=1x4+2x83x10+15x14+4x18

格式

输入格式:第一行两个整数 n n n m m m,分别表示 L A L_A LA L B L_B LB 的项数;
     接下来 n n n 行,每行输入 L A L_A LA 的每一项的信息,两个整数分别表示该项的系数 c o e f coef coef 和次数 e x p n expn expn,输入保证次数递增;
     接下来 m m m 行,每行输入 L B L_B LB 的每一项的信息,两个整数分别表示该项的系数 c o e f coef coef 和次数 e x p n expn expn,输入保证次数递增。
输出格式:输出 k k k 行, k k k L C L_C LC 的项数,每行输出 L C L_C LC 的每一项的信息,两个整数分别表示该项的系数 c o e f coef coef 和次数 e x p n expn expn,输出按次数递增。

样例 1

输入:4 5
   1 0
   -10 6
   2 8
   7 14
   -1 4
   10 6
   -3 10
   8 14
   4 18

输出:1 0
   -1 4
   2 8
   -3 10
   15 14
   4 18

备注

对于 100 100% 100 的数据: 0 ≤ n , m ≤ 1 , 000 , 000 , − 1 , 000 ≤ c o e f ≤ 1 , 000 , − 1 , 000 , 000 , 000 ≤ e a p n ≤ 1 , 000 , 000 , 000 0 ≤n, m ≤ 1,000,000,-1,000 ≤coef ≤1,000,-1, 000,000,000 ≤eapn ≤ 1, 000,000,000 0n,m1,000,0001,000coef1,0001,000,000,000eapn1,000,000,000


相关知识点:链表


题解


考察了链表的相关知识,下面直接给出求解本题的完整代码(已 AC):

/*
	MT2133 一元多项式的加法 
*/ 

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

const int MAX = 2e6+5;
struct Node{
	int coef, expn, next; 
};

int head,tail,pos;
int coefA[MAX], expnA[MAX], coefB[MAX], expnB[MAX];
Node nodes[MAX];

void insert(int now, int a, int b){
	nodes[++pos].coef = a;
	nodes[pos].expn = b;
	nodes[pos].next = nodes[now].next;
	nodes[now].next = pos;
	if(!nodes[pos].next) tail = pos;
}

int main( )
{ 
	int n, m; cin>>n>>m;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&coefA[i],&expnA[i]);
		// cin>>coefA[i]>>expnA[i];
	for(int i=1;i<=m;i++) 
		scanf("%d%d",&coefB[i],&expnB[i]);
		// cin>>coefB[i]>>expnB[i];
	
	int l = 1, r = 1;
	while(l<=n && r<=m){
		if(expnA[l] == expnB[r]){
			insert(tail, coefA[l]+coefB[r], expnA[l]);
			l++,r++;
		}else{
			if(expnA[l] < expnB[r]){
				insert(tail, coefA[l], expnA[l]);
				l++;
			}else{
				insert(tail, coefB[r], expnB[r]);
				r++;
			}
		}
	}
	while(l <= n){
		insert(tail, coefA[l], expnA[l]);
		l++;
	}
	while(r <= m){
		insert(tail, coefB[r], expnB[r]);
		r++;
	}
	
	for(int i=nodes[head].next; i!=0; i=nodes[i].next)
		if(nodes[i].coef != 0){
			printf("%d %d\n",nodes[i].coef,nodes[i].expn);
			// cout<<nodes[i].coef<<" "<<nodes[i].expn<<endl;
		}
	
    return 0;
}

END


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

theSerein

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

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

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

打赏作者

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

抵扣说明:

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

余额充值