C++ 并查集

并查集

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入格式

第一行包含两个整数 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值