The ideas behind disjoint-set union and the Kruskal reconstruction tree are very similar, and both can be used to process connectivity-related problems. This article introduces applications of the disjoint-set union technique through examples.
A
A
There are vertices, all isolated initially.
Next, there are edge-addition operations. Operation adds an undirected edge between and . Let denote the earliest operation after which vertices and become connected, that is, after operation .
After all operations, find the value of .
This is a basic application of disjoint-set union: maintain the size of each component and consider the contribution of every operation. If and belong to two different components during operation , merge the two components and add the product of their sizes multiplied by to the answer. The time complexity is .
B
B
There are vertices, all isolated initially.
Next, there are edge-addition operations. Operation adds an undirected edge between and .
Next, there are queries. In query , determine after which operation vertices and first become connected.
When merging components in disjoint-set union, maintain a “disjoint-set union spanning tree”: if and belong to different components during operation , include the edge in the spanning tree, with edge weight . A query then asks for the maximum edge weight on the path from to , which can be maintained using binary lifting or heavy-light decomposition. The time complexity is .
Another method is to maintain a Kruskal reconstruction tree. Its essence is the same as that of the disjoint-set union spanning tree, and its complexity is also the same.
C
C
There are vertices, all isolated initially.
Next, there are edge-addition operations. Operation adds an undirected edge between and .
Next, there are queries. In query , determine the size of the connected component containing vertex after operation .
Offline algorithm: sort the queries in increasing order of . Process the queries while adding edges with a disjoint-set union. The time complexity is .
Online algorithm: the online algorithm for this problem can use only a Kruskal reconstruction tree. The difference from disjoint-set union is that, when and belong to different components during operation , Kruskal creates a new vertex , then connects the roots of the components containing and to as 's two children. Let the vertex weight of be . The initial vertices have vertex weight .
For a query, we only need to find the largest connected component containing in the reconstruction tree such that the maximum vertex weight in the component does not exceed . The answer is the number of vertices in this component whose vertex weight is , that is, the number of leaf vertices.
Since the operation indices are increasing, the vertex weight of a parent in the reconstruction tree is always greater than that of its child. Therefore, on the path from to the root, we can use binary lifting to find the vertex with the largest weight not exceeding . This gives the answer. The time complexity is .
D
D
Given a binary sequence of length , initially all , perform operations:
- Set .
- Find the leftmost position whose value is among .
Maintain a disjoint-set union where is the position of the first among . Initially, .
For an operation setting , do nothing if was already ; otherwise, set .
The time complexity is . Using union by rank is somewhat cumbersome to implement, but it is still possible; in that case, the time complexity can be .
E
E
Given three sequences , , and of positive integers of length , enumerate and find the maximum value of .
There are also many ways to solve this problem; here we focus on the disjoint-set union approach. Consider in decreasing order of value. Equivalently, add a vertex at position , then merge it with the components containing positions and if those positions already contain vertices. Store the maximum value of and the maximum value of in each component, and update the answer during merges. The time complexity is .
F
F
Given a tree with vertices, perform operations:
- Add an edge from to .
- Ask whether there are at least two edge-disjoint paths between and .
The query can be transformed into asking whether and lie on the same simple cycle. Following the idea of contracting biconnected components, whenever an edge is added between and , contract all vertices on the tree path from to . If the tree paths corresponding to two added edges and intersect, those edges are contracted together.
In other words, an edge-addition operation can be viewed as covering every edge on the tree path from to once. The query becomes checking whether there is an uncovered edge on the path from to . If there is none, then and belong to the same biconnected component, and hence to the same simple cycle.
Use disjoint-set union to maintain this structure. Root the tree, and let be the first uncovered edge on the path from to the root. For each edge-addition operation, repeatedly jump using disjoint-set union. After covering an edge, merge the of the corresponding vertex with its parent. Each edge is covered at most once, so the total complexity is . Union by rank can likewise achieve .
The maintenance method is similar to the tree version of D.
G
G
An undirected graph has vertices, all isolated initially (that is, it has no edges).
Next, there are edge-addition operations. Operation adds an undirected edge between and .
After every operation, find the number of bridges in the graph.
An edge in is called a bridge if deleting it increases the number of connected components; then is a bridge.
The algorithm must be online.
This problem tests one’s understanding of disjoint-set union. Use disjoint-set union to maintain connectivity. For the bridge tree, maintain a rooted tree and let denote the parent of vertex ; this is disjoint-set union without path compression.
If, during operation , and belong to the same connected component, contract the vertices on the path between and in the bridge tree, which can be maintained with disjoint-set union. Each contraction decreases the number of biconnected components by , and there can be at most contractions, so the disjoint-set union complexity of the contraction part is .
To contract the path, first find the LCA of and in the bridge tree. Maintain a marker array. Starting from and , alternately jump upward one ancestor at a time and mark every visited vertex. Once a vertex that was marked previously is reached, it is the LCA of and . The complexity is linear in the length of the path from to , which is acceptable.
If and belong to different connected components, merge the two components and increase the number of bridges by . We must connect the two bridge trees by adding an edge from to . Thus, one of the trees must be rerooted and attached to the other. Using the idea of heuristic merging, reroot the tree with fewer vertices. The total complexity is .
Therefore, the total complexity of the algorithm is .
Summary
Disjoint-set union and Kruskal reconstruction trees have many points in common, and the disjoint-set union optimization of union by rank is itself an application of heuristic merging. Therefore, flexible use of disjoint-set union can conveniently handle many graph-theoretic problems related to connectivity.
Part of this page is adapted from the blog post Finding Bridges Online and its English-language edition Finding Bridges Online. The Russian version is licensed under Public Domain + Leave a Link; the English version is licensed under CC-BY-SA 4.0.