数据结构--并查集

思路:

1. 初始化:

假如有编号为1,2,3,.., n的n个元素,我们用一个数组p来存储每个元素的父节点。一开始,我们先将它们的父节点设为自己

int p[N];
for(int i = 1;i <= n;i ++)
    p[i] = i;

2. 查询

找到i的祖先直接返回,未进行路径压缩

int find(int i){
    if(p[i] == i)
        return i;
    else return find(p[i]);
}

3.合并

void union(int i,int j){
    p[find(i)] = find(j); //i的祖先指向i的祖先。
}

路径压缩:

int find(int x){  //返回x的祖宗节点 + 路径压缩
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}

例题:836. 合并集合 - AcWing题库

一共有 n 个数,编号是 1∼n,最开始每个数各自在一个集合中。

现在要进行 m 个操作,操作共有两种:

  1. M a b,将编号为 a 和 b 的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
  2. Q a b,询问编号为 a 和 b 的两个数是否在同一个集合中;

输入格式

第一行输入整数 n 和 m。

接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。

输出格式

对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No

每个结果占一行。

数据范围

1≤n,m≤10^5

输入样例:

4 5
M 1 2
M 3 4
Q 1 2
Q 1 3
Q 3 4

输出样例:

Yes
No
Yes

代码:

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include

const int N = 1e5 + 10;
using namespace std;
typedef pair PII;
int n,m;
int p[N];
int find(int x){  //返回x的祖宗节点 + 路径压缩
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}
//find函数找祖先
int main(){
	cin >> n >> m;
	for(int i = 1;i <= n;i ++)
		p[i] = i;
	while(m --){ 
		char op[2];
		int a,b;
		scanf("%s%d%d",op,&a,&b);
		if(op[0] == 'M') p[find(a)] = find(b);//a->b
		else{
			if(find(a) == find(b)) cout << "Yes" << endl;
			else cout << "No" << endl;
		}
	}
	return 0;
}

你可能感兴趣的:(数据结构)