Joint search set
Background and significance
And look up the set. In some set application problems with N elements, we usually make each element form a single element set at the beginning, and then merge the sets of elements belonging to the same group in a certain order. In the meantime, we should repeatedly find out which set an element is in. In recent years, this kind of problems have repeatedly appeared in the international and domestic competitions of informatics. Its characteristic is that it does not seem complex, but the amount of data is huge. If it is described with normal data structure, it is often too large in space for the computer to bear; Even if it barely passes in space, the running time complexity is also very high. It is impossible to calculate the results required by the test questions within the running time specified in the competition (1 ~ 3 seconds), which can only be described by parallel search.
Union query set is a tree data structure, which is used to deal with the merging and query of some disjoint sets. It is often represented by forest in use.
basic operation
initialization
Initialize the set where each point is located as itself.
Generally speaking, this step only needs to be executed once every time the data structure is used. Regardless of the implementation method, the time complexity is.
// Initialization, assuming that the node number is 1~n for (int i = 1; i <= n; i ++ ) p[i] = i;
lookup
Find the collection where the element is located, that is, the root node.
// Returns the ancestor node of x int find(int x) { if (p[x] != x) p[x] = find(p[x]); return p[x]; }
merge
Merge the set of two elements into one set.
Generally speaking, before merging, you should first judge whether the two elements belong to the same set, which can be realized by the "find" operation above.
// Merge the two sets of a and b: p[find(a)] = find(b); //Connect the ancestor node of a set to the ancestor node of b
Personal understanding
Each node is initialized as a set, and each set has a unique ancestor node (this is used to distinguish whether it is the same set). Multiple nodes are a set. The set exists in the form of a tree, and the root node is the ancestor node of the set. Finding the set to which a node belongs is to find its ancestor node. Each node stores its parent node, that is, the parent node (except the root node and ancestor node) can be found through its own node, and the root node can be found by recursively finding the parent node.
To merge two sets, you only need to connect the root nodes of the two sets together.
subject
Topic source AcWing question 827
Given an undirected graph containing n points (numbered 1 ∼ n), there are no edges in the graph at the beginning.
There are m operations to be performed. 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, and a and b may be equal;
- Q2 a, the number of midpoint of the connected block where query point a is located;
Input format
On the first line, enter the integers n and m.
Next m lines, each line contains an operation instruction, which is one of C a b, Q1 a b or Q2 a.
Output format
For each query instruction Q1 A and b, if a and b are in the same connected block, Yes is output, otherwise No is output.
For each query instruction Q2a, an integer is output to represent the number of midpoint of the connected block where point a is located
One line for each result.
Data range
1 ≤ n,m ≤ 105
Input example:
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
Output example:
Yes
2
3
code
#include <iostream> using namespace std; const int N = 100010; int p[N]; int s[N]; //Find the ancestor node of the connected block where x is located //Ancestral node feature p[x] == x 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 = 1; i <= n;i ++){ p[i] = i; s[i] = 1;//The initial number of each set is 1 } while(m --){ char op[2]; int a,b; scanf("%s", op); if(op[0] == 'C') { scanf("%d%d", &a,&b); if(find(a) == find(b)) continue; s[find(b)] += s[find(a)]; //Add the number of a-connected blocks to b-connected blocks p[find(a)] = find(b); // Connect a connected block to b connected block } else if(op[1] == '1'){ scanf("%d%d", &a,&b); if(find(a) == find(b)) puts("Yes"); else puts("No"); } else{ scanf("%d", &a); printf("%d\n",s[find(a)]); } } return 0; }
Problem solving ideas
Each connected block is a set. The operations to be done are merging the set, finding out whether the two nodes are in the same set and how many nodes there are in the set. Obviously, the first two operations are the operations of merging and querying sets. To query the number of set elements later, we can create an array to represent the number of sets where a node is located. Because storing the number of sets on each node will cause data duplication, we can store a size [] array on the ancestor node of each set.