Union check and related deformation

1. The problem to be solved

There are n numbers in total, numbered from 1 to n, and each number is in a set at the beginning.

Now there are m operations to be performed, and there are two types of operations:

M a b, merge the sets of the two numbers numbered a and b, if the two numbers are already in the same set, ignore this operation; , ask
Q a bwhether the two numbers numbered a and b are in the same set;

2. Check and set

2.1 Supported operations

  • Merge the two collections
  • Ask if two numbers are in the same set

2.2 Methods to solve the problem

Build each set into a tree, and each node of the tree is a number in the same set. The number of the tree is the number of the root node.
To do this, for each node i, its parent node p[i] needs to be stored.

2.3 Questions to think about

  • How to judge the root of the tree
    The characteristic of the root node is that its parent node is itself
if(p[x] == x) x就是根节点
  • How to find the number of the set where the number x is located
while(x != p[x]) x = p[x];

As long as x is not the root node, x keeps going up until x is the root of the tree. The number of the root of the tree is the number of the set

  • How to combine the sets of two numbers
    p[x] is the set number of x, p[y] is the set number of y
p[x] == y
  • Ask if two nodes are in a set:
if(p[i] == p[j]) Yes
else No

2.4 Optimization

When the depth of the tree is very large, each time the number of the set where x is judged has to go many layers. To this end, the "path compression" method is adopted. After finding the root node of x, the nodes on the entire path are directly pointed to the root node

3. Code implementation

#include<iostream>
using namespace;
const int N = 100010;
// 存放每个节点的父节点
int p[N];
// n代表数的个数,m代表操作的个数
int n,m;

// 寻找x的根节点+路径压缩
int find(int x){
    
    
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}
int main(){
    
    
	scanf("%d%d", &n, &m);
	//初始化各个节点的父节点
	for(int i = 0; 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);
		// 询问两个数是否在同一个集合中
		else{
    
    
			if(find(a) == find(b)) puts("Yes");
			else puts("No");
		}
	}	
	return 0;
}

4. Union search application two-number of midpoints in connected blocks

4.1 Title Description

Given an undirected graph containing n vertices (numbered 1∼n), initially there are no edges in the graph.

Now there are m operations to be performed, and there are three types of operations:

C a b, connect an edge between point a and point b, a and b may be equal;
Q1 a b, ask whether point a and point b are in the same connected block, a and b may be equal;
Q2 a, ask about the point in the connected block where point a is located quantity;

4.2 Issues to consider

Each connected block is still represented by a tree.
The first two operations are consistent with the operations to be performed by the union search. This question needs to consider the number of midpoints of a connected block.
Let another one int count[N]represent the number of points in each set. Therefore, when initializing the parent node of the point, initialize the number of points contained in each set.

4.3 Code implementation

#include<iostream>
using namespace std;

const int N = 100010;

// 存放每个节点的父节点,一共有不超过N个节点
int p[N];
// 存放每个集合中点的大小
int cnt[N];

// 查找每个点的父节点+路径压缩
int find(int x){
    
    
	if(p[x] != x) p[x] = find(p[x]);
	return p[x];
}

int main(){
    
    
	int n, m;
	scanf("%d%d", &n, &m);
	// 初始化
	for(int i = 0; i < n; i++){
    
    
		p[i] = i;
		cnt[i] = 1;
	}
	while(m--){
    
    
		string op;
		int a, b;
		cin >> op;
		// 将两个数所在集合合并
		if(op == "C"){
    
    
			scanf("%d%d", &a, &b);
			// 只有a,b不在一个连通块里才需要合并
			if(find(a) != find(b)){
    
    
				// 一定先合并数量再改变树的结构
				cnt[find(b)] += cnt[find(a)];
				p[find(a)] = find(b);
			}
		}
		// 判断两个数是否在同一集合
		else if(op == "Q1"){
    
    
			scanf("%d%d", &a, &b);
			if(find(a) == find(b)) printf("Yes\n");
			else printf("No\n");
		}
		// 询问连通块中点的数量
		else{
    
    
			scanf("%d", &a);
			printf("%d\n", cnt[find(a)];
		}
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43943476/article/details/127439542