并查集专题
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 5≤n≤10000,2≤q≤2000,1≤a,b≤20000,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 1≤m,n≤100000,0≤si≤100
相关知识点:
并查集
题解
本题依然考察了并查集的使用,下面直接给出完整代码(已 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) n,m(1≤n,m≤1e5),表示人数,和暧昧关系的数量;
接下来m行,每行两个整数 a , b ( 1 ≤ a , b ≤ n ) a,b (1≤a, b≤n) a,b(1≤a,b≤n),表示 a , b a,b a,b 之间存在暧昧关系;
最后一行一个整数 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=1−10x6+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+10x6−3x10+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=1−x4+2x8−3x10+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 0≤n,m≤1,000,000,−1,000≤coef≤1,000,−1,000,000,000≤eapn≤1,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;
}