并查集
题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数 N,M ,表示共有 N 个元素和 M 个操作。
接下来 M 行,每行包含三个整数 Zi,Xi,Yi 。
当 Zi=1时,将 Xi与 Yi所在的集合合并。
当 Zi=2时,输出 Xi 与 Yi 是否在同一集合内,是的输出 Y
;否则输出 N
。
输出格式
对于每一个 Zi=2 的操作,都有一行输出,每行包含一个大写字母,为 Y
或者 N
。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
int find(int x)
{
if(x!=acc[x]) acc[x] = find(acc[x]);
return acc[x];
}
signed main()
{
IOS;
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++) acc[i] = i;
while(m--)
{
int z,x,y;
cin>>z>>x>>y;
if(z==1)
{
int t1 = find(x),t2 = find(y);
if(t1!=t2) acc[t1] = t2;
}
if(z==2)
{
int t1 = find(x),t2 = find(y);
if(t1 == t2) cout<<"Y"<<"\n";
else cout<<"N"<<"\n";
}
}
return 0;
}
亲戚
题目背景
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。
题目描述
规定:xx 和 yy 是亲戚,yy 和 zz 是亲戚,那么 xx 和 zz 也是亲戚。如果 xx,yy 是亲戚,那么 xx 的亲戚都是 yy 的亲戚,yy 的亲戚也都是 xx 的亲戚。
输入格式
第一行:三个整数 n,m,p(n,m,p≤5000),分别表示有 n 个人,m 个亲戚关系,询问 p 对亲戚关系。
以下 m 行:每行两个数 Mi,Mj,1≤Mi, Mj≤n,表示 Mi 和 Mj 具有亲戚关系。
接下来 p 行:每行两个数Pi,Pj,询问 PiPi 和 PjPj 是否具有亲戚关系。
输出格式
p 行,每行一个 Yes
或 No
。表示第 i 个询问的答案为“具有”或“不具有”亲戚关系。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
int find(int x)
{
if(x!=acc[x]) acc[x] = find(acc[x]);
return acc[x];
}
signed main()
{
IOS;
int n,m,p;
cin>>n>>m>>p;
for(int i = 1;i<=n;i++) acc[i] = i;
int x,y;
for(int i = 1;i<=m;i++)
{
cin>>x>>y;
int t1 = find(x),t2 = find(y);
acc[t1] = t2;
}
for(int i = 1;i<=p;i++)
{
int a,b;
cin>>a>>b;
int t3 = find(a),t4 = find(b);
if(t3==t4) cout<<"Yes"<<"\n";
else cout<<"No"<<"\n";
}
return 0;
}
一中校运会之百米跑
题目背景
在一大堆秀恩爱的 ** 之中,来不及秀恩爱的苏大学神踏着坚定(?)的步伐走向了 100100 米跑的起点。这时苏大学神发现,百米赛跑的参赛同学实在是太多了,连体育老师也忙不过来。这时体育老师发现了身为体育委员的苏大学神,便来找他帮忙。
可是苏大学神需要热身,不然跑到一半就会抽(筋)、于是他就找到了你。。。如果你帮助体育老师解决了问题,老师就会给你 55 个积分。
题目描述
假设一共有 NN(2≤N≤2×104)个参赛选手。(尼玛全校学生都没这么多吧)
老师会告诉你这 N 个选手的名字。
接着会告诉你 MM(1≤M≤106)句话,即告诉你学生 A 与学生 B 在同一个组里。
如果学生 A 与学生 B 在同一组里,学生 B 与学生 C 也在同一组里,就说明学生 A 与学生 C 在同一组。
然后老师会问你 K(1≤K≤106)句话,即学生 X 和学生 Y 是否在同一组里。
若是则输出 Yes.
,否则输出 No.
。
输入格式
第一行输入 N 和 M。
接下来 N 行输入每一个同学的名字。
再往下 M 行每行输入两个名字,且保证这两个名字都在上面的 N 行中出现过,表示这两个参赛选手在同一个组里。
再来输入 K。
接下来输入 K 个体育老师的询问。
输出格式
对于每一个体育老师的询问,输出 Yes.
或 No.
。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
map<string,string > acc;
string find(string x)
{
if(x==acc[x]) return x;
else return acc[x] = find(acc[x]);
}
signed main()
{
IOS;
int n,m;
string s;
string a,b;
cin>>n>>m;
for(int i = 1;i<=n;i++)
{
cin>>s;
acc[s] = s;
}
for(int i = 1;i<=m;i++)
{
cin>>a>>b;
string t1 = find(a),t2 = find(b);
acc[t1] = t2;
}
int k;
cin>>k;
for(int i = 1;i<=k;i++)
{
cin>>a>>b;
string t3 = find(a),t4 = find(b);
if(t3==t4) cout<<"Yes."<<"\n";
else cout<<"No."<<"\n";
}
return 0;
}
SKA-Piggy Banks
题目描述
Byteazar the Dragon 拥有 N 个小猪存钱罐。每一个存钱罐能够用相应的钥匙打开或者被砸开。Byteazar 已经将钥匙放入到一些存钱罐中。现在已知每个钥匙所在的存钱罐,Byteazar 想要买一辆小汽车,而且需要打开所有的存钱罐。然而,他想要破坏尽量少的存钱罐,帮助 Byteazar 去决策最少要破坏多少存钱罐。
输入格式
第一行包括一个整数 N (1≤N≤1000000),表示 Byteazar the Dragon 拥有的存钱罐的数量。
存钱罐(包括它们对应的钥匙)从 1 到 N 编号。
接下来有 N 行:第 i+1 行包括一个整数 x,表示第 i 个存钱罐对应的钥匙放置在了第 x 个存钱罐中。
输出格式
仅一行:包括一个整数,表示能打开所有存钱罐的情况下,需要破坏的存钱罐的最少数量。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
int find(int x)
{
if(x==acc[x]) return x;
else return acc[x] = find(acc[x]);
}
signed main()
{
IOS;
int n;
cin>>n;
int sum = 0;
for(int i = 1;i<=n;i++) acc[i] = i;
for(int i = 1;i<=n;i++)
{
int x;
cin>>x;
acc[find(i)] = find(x);
}
for(int i = 1;i<=n;i++)
{
if(acc[i]==i) sum++;
}
cout<<sum;
return 0;
}
家谱
题目背景
现代的人对于本家族血统越来越感兴趣。
题目描述
给出充足的父子关系,请你编写程序找到某个人的最早的祖先。
输入格式
输入由多行组成,首先是一系列有关父子关系的描述,其中每一组父子关系中父亲只有一行,儿子可能有若干行,用 #name
的形式描写一组父子关系中的父亲的名字,用 +name
的形式描写一组父子关系中的儿子的名字;接下来用 ?name
的形式表示要求该人的最早的祖先;最后用单独的一个 $
表示文件结束。
输出格式
按照输入文件的要求顺序,求出每一个要找祖先的人的祖先,格式为:本人的名字 + 一个空格 + 祖先的名字 + 回车。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
string fa;
int acc[N],cnt = 0;
map<string,int > mp;
map<int,string > pm;
int find(int x)
{
if(acc[x]==x) return x;
else return acc[x]=find(acc[x]);
}
signed main()
{
IOS;
for(int i = 1;i<=1e6;i++) acc[i] = i;
while(1)
{
char op;
string s;
cin>>op;
if(op=='$') break;
else cin>>s;
if(mp[s]==0)
{
cnt++;
mp[s] = cnt;
pm[cnt] = s;
}
if(op=='#') fa = s;
if(op=='+')
{
int t1 = find(mp[s]),t2 = find(mp[fa]);
if(t1!=t2) acc[t1] = t2;
}
if(op=='?')
{
cout<<s<<" "<<pm[find(mp[s])]<<"\n";
}
}
return 0;
}
村村通
题目描述
某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程" 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?
输入格式
输入包含若干组测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 n 和道路数目 m ;随后的 m 行对应 m 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 1 到 n 编号。
注意:两个城市间可以有多条道路相通。
在输入数据的最后,为一行一个整数 0,代表测试数据的结尾。
输出格式
对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
int n,m,a,b;
int find(int x)
{
if(acc[x]==x) return x;
else return acc[x]=find(acc[x]);
}
signed main()
{
IOS;
while(1)
{
int sum=0;
cin>>n;
if(n==0) return 0;
cin>>m;
for(int i=1;i<=n;i++) acc[i]=i;
for(int i=1;i<=m;i++)
{
cin>>a>>b;
int t1=find(a),t2=find(b);
acc[t1]=t2;
}
for(int i=1;i<=n;i++)
{
if(acc[i]==i)
sum++;
}
cout<<sum-1<<"\n";
}
return 0;
}
朋友
题目背景
小明在 A 公司工作,小红在 B 公司工作。
题目描述
这两个公司的员工有一个特点:一个公司的员工都是同性。
A 公司有 N 名员工,其中有 P 对朋友关系。B 公司有 M 名员工,其中有 Q 对朋友关系。朋友的朋友一定还是朋友。
每对朋友关系用两个整数 (Xi,Yi) 组成,表示朋友的编号分别为 Xi,Yi。男人的编号是正数,女人的编号是负数。小明的编号是 1,小红的编号是 −1。
大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。
输入格式
输入的第一行,包含 44 个空格隔开的正整数 N,M,P,Q。
之后 P 行,每行两个正整数 Xi,Yi。
之后 Q 行,每行两个负整数 Xi,Yi。
输出格式
输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
int macc[N];
int n,m,p,q;
int find(int x)
{
if(acc[x]==x) return x;
else return acc[x]=find(acc[x]);
}
signed main()
{
IOS;
cin>>n>>m>>p>>q;
int sum1 = 0,sum2 = 0;
int x,y;
int a,b;
for(int i = 1;i<=n+m;i++) acc[i] = i;
for(int i = 1;i<=p;i++)
{
cin>>x>>y;
int t1 = find(x),t2 = find(y);
acc[t1] = t2;
}
for(int i = 1;i<=q;i++)
{
cin>>a>>b;
a*=-1,b*=-1;
int t3 = find(a+n),t4 = find(b+n);
acc[t3] = t4;
}
for(int i = 1;i<=n;i++)
{
if(find(i)==find(1)) sum1++;
}
for(int i = 1;i<=n+m;i++)
{
if(find(i)==find(n+1)) sum2++;
}
cout<<min(sum1,sum2);
return 0;
}
修复公路
题目背景
A 地区在地震过后,连接所有村庄的公路都造成了损坏而无法通车。政府派人修复这些公路。
题目描述
给出 A 地区的村庄数 N,和公路数 M,公路是双向的。并告诉你每条公路的连着哪两个村庄,并告诉你什么时候能修完这条公路。问最早什么时候任意两个村庄能够通车,即最早什么时候任意两条村庄都存在至少一条修复完成的道路(可以由多条公路连成一条道路)。
输入格式
第 1 行两个正整数 N,M。
下面 M 行,每行 3 个正整数 x,y,t ,告诉你这条公路连着 x,y 两个村庄,在时间 t 时能修复完成这条公路。
输出格式
如果全部公路修复完毕仍然存在两个村庄无法通车,则输出 −1,否则输出最早什么时候任意两个村庄能够通车。
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define PII pair<int,int >
#define int long long
#define IOS std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+10;
int acc[N];
struct node{int x,y,t;} va[N];
bool operator < (node a,node b){return a.t<b.t;}
int find(int x){if(x!=acc[x])acc[x]=find(acc[x]);return acc[x];}
int n,m,sum,maxn;
signed main()
{
IOS;
cin>>n>>m;
for(int i=1;i<=n;i++)acc[i]=i;
for(int i=1;i<=m;i++)
cin>>va[i].x>>va[i].y>>va[i].t;
sort(va+1,va+1+m);
for(int i=1;i<=m;i++)
{
int x=find(va[i].x),y=find(va[i].y);
if(x==y)continue;
acc[x]=y;
sum++;
maxn=max(maxn,va[i].t);
}
if(sum!=n-1)
cout<<-1<<"\n";
else cout<<maxn<<"\n";
return 0;
}