题目描述
一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。
现在要进行 m 个操作,操作共有两种:
M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;
输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。
输出格式
对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No。
每个结果占一行。
数据范围
1≤n,m≤1e5
输入样例:
4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4
输出样例:
Yes
No
Yes
算法1
#include<iostream>
using namespace std;
const int N=100010;
int p[N];//father数组,存储元素的父节点
int find(int x)//返回x所在集合编号,即其祖宗节点+路径压缩
{
if(p[x]!=x)//若x不是祖宗节点
{
p[x]=find(p[x]);//让父节点=其祖宗节点
}
return p[x];//返回父节点(已经是祖宗节点)
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;//初始化,刚开始每个数都自成一个集合,都是根节点
char op[2];
int a,b;
while(m--)
{
scanf("%s%d%d",op,&a,&b);//此处输入op即可,而非op[0]
if(op[0]=='M')//合并集合
{
p[find(a)]=find(b);//让a的祖宗节点的父亲指向=b的祖宗节点
}
else //若二者祖宗节点一致则为同一集合
{
if(find(a)==find(b)) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
算法2
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* Created by Yolanda on 2021/6/2 20:27
*/
public class Main {
static int N=100010;
static int[] p=new int[N];
static int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String[] s=br.readLine().split(" ");
int n=Integer.parseInt(s[0]);
int m=Integer.parseInt(s[1]);
for(int i=1;i<=n;i++) p[i]=i;
String op;
int a,b;
while(m-->0)
{
String[] ss=br.readLine().split(" ");
op=ss[0];
a=Integer.parseInt(ss[1]);
b=Integer.parseInt(ss[2]);
if(op.equals("M"))
{
p[find(a)]=find(b);
}
else
{
if(find(a)==find(b)) System.out.println("Yes");
else System.out.println("No");
}
}
}
}