洛谷篇 并查集模板

 自己写着玩的

P3367

# 【模板】并查集

## 题目描述

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

## 输入格式

第一行包含两个整数 $N,M$ ,表示共有 $N$ 个元素和 $M$ 个操作。

接下来 $M$ 行,每行包含三个整数 $Z_i,X_i,Y_i$ 。

当 $Z_i=1$ 时,将 $X_i$ 与 $Y_i$ 所在的集合合并。

当 $Z_i=2$ 时,输出 $X_i$ 与 $Y_i$ 是否在同一集合内,是的输出 
 `Y` ;否则输出 `N` 。

## 输出格式

对于每一个 $Z_i=2$ 的操作,都有一行输出,每行包含一个大写字母,为 `Y` 或者 `N` 。

## 样例 #1

### 样例输入 #1

```
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
```

### 样例输出 #1

```
N
Y
N
Y
```

## 提示

对于 $30\%$ 的数据,$N \le 10$,$M \le 20$。

对于 $70\%$ 的数据,$N \le 100$,$M \le 10^3$。

对于 $100\%$ 的数据,$1\le N \le 10^4$,$1\le M \le 2\times 10^5$,$1 \le X_i, Y_i \le N$,$Z_i \in \{ 1, 2 \}$。

4 7                
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
N
Y
N
Y

模板函数 init() findFather(x) Union(a,b);

#include<iostream>
#include<stdio.h>
#include <algorithm>
#include<string>
#include <bits/stdc++.h>
using namespace std;
const int maxn=100000;
int father[maxn];
int N,M; 
void init()
{
	for(int i = 0; i < N; i++){
		father[i] = i;    //在并查集使用前,先让其为自身。因为一开始每个元素都是独立的一个集合
	}
}
//递归实现
int findFather(int x){
    if(x == father[x])    return x;
    else{
//        return findFather(father[x]); 超时!!! 
	return father[x]=findFather(father[x]);
    }
}

//合并
void Union(int a, int b){
    int faA = findFather(a);
    int faB = findFather(b);
    if(faA != faB){    //若a和b不属于同一个集合
        father[faA] = faB; 
    }
}

int main()
{
	int z,a,b;

	cin>>N>>M;
	init();
	
		for(int i=0;i<M;i++)
		{
			cin>>z>>a>>b;
			
			if(z==1)
//				father[findFather(a)]=findFather(b);
				Union(a,b);
			if(z==2){
				if(findFather(a)==findFather(b))
					cout<<"Y"<<endl;
				else
					cout<<"N"<<endl; 
			}
				
		}

	return 0;
}
 

P2078

# 朋友

## 题目背景

小明在 A 公司工作,小红在 B 公司工作。

## 题目描述

这两个公司的员工有一个特点:一个公司的员工都是同性。

A 公司有 $N$ 名员工,其中有 $P$ 对朋友关系。B 公司有 $M$ 名员工,其中有 $Q$ 对朋友关系。朋友的朋友一定还是朋友。

每对朋友关系用两个整数 $(X_i,Y_i)$ 组成,表示朋友的编号分别为 $X_i,Y_i$。男人的编号是正数,女人的编号是负数。小明的编号是 $1$,小红的编号是 $-1$。

大家都知道,小明和小红是朋友,那么,请你写一个程序求出两公司之间,通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

## 输入格式

输入的第一行,包含 $4$ 个空格隔开的正整数 $N,M,P,Q$。

之后 $P$ 行,每行两个正整数 $X_i,Y_i$。

之后 $Q$ 行,每行两个负整数 $X_i,Y_i$。

## 输出格式

输出一行一个正整数,表示通过小明和小红认识的人最多一共能配成多少对情侣(包括他们自己)。

## 样例 #1

### 样例输入 #1

```
4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3
```

### 样例输出 #1

```
2
```

## 提示

对于 $30 \%$ 的数据,$N,M \le 100$,$P,Q \le 200$;

对于 $80 \%$ 的数据,$N,M \le 4 \times 10^3$,$P,Q \le 10^4$;

对于 $100 \%$ 的数据,$N,M \le 10^4$,$P,Q \le 2 \times 10^4$。

4 3 4 2
1 1
1 2
2 3
1 3
-1 -2
-3 -3
2

男女单独使用并查集模板函数,然后最后求最小值。记住是从1开始到<=的,不能是从0开始到<的,毕竟小明小红至少一对。

然后就是女生的是负数,转变一下,就正常套用自己的并查集模板函数就可。

#include<iostream>
#include<stdio.h>
#include <algorithm>
#include<string>
#include <bits/stdc++.h>
using namespace std;
const int maxn=10000;
int father1[maxn];//男 
int father2[maxn];//Nv
int N,M,P,Q; 
int a,b;//男
int m,n;//女 

void init()
{
	for(int i = 1; i <= N; i++){
		father1[i] = i;    //在并查集使用前,先让其为自身。因为一开始每个元素都是独立的一个集合
	}
	for(int i = 1; i <=M; i++){
		father2[i] = i;    //在并查集使用前,先让其为自身。因为一开始每个元素都是独立的一个集合
	}
}
//递归实现
int findFather1(int x){
    if(x == father1[x])    return x;
    else{
//        return findFather(father[x]); 超时!!! 
	return father1[x]=findFather1(father1[x]);
    }
}
//递归实现
int findFather2(int x){
    if(x == father2[x])    return x;
    else{
//        return findFather(father[x]); 超时!!! 
	return father2[x]=findFather2(father2[x]);
    }
}
//合并
void Union1(int a, int b){
    int faA = findFather1(a);
    int faB = findFather1(b);
    if(faA != faB){    //若a和b不属于同一个集合
        father1[faA] = faB; 
    }
}
void Union2(int a, int b){
    int faA = findFather2(a);
    int faB = findFather2(b);
    if(faA != faB){    //若a和b不属于同一个集合
        father2[faA] = faB; 
    }
}
int main()
{
	cin>>N>>M>>P>>Q;
	init(); 
	int cnt1=0,cnt2=0; 

		
	for(int i=1;i<=P;i++)
	{	
		cin>>a>>b;
		Union1(a,b);
		
	}
	
	
	for(int i=1;i<=Q;i++)
	{
			cin>>m>>n;
		m=-m;
		n=-n;
		Union2(m,n);
	
	}	

	for(int i=1;i<=N;i++){
			if(findFather1(i)==findFather1(1))
			cnt1++;
		}
	for(int i=1;i<=M;i++){
			if(findFather2(i)==findFather2(1))
			cnt2++;
	}
	int ans=min(cnt1,cnt2);

		cout<<ans<<endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值