自己写着玩的
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;
}