Applications of Disjoint-Set Union

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 nn vertices, all isolated initially.

Next, there are mm edge-addition operations. Operation ii adds an undirected edge between aia_i and bib_i. Let L(i,j)L(i,j) denote the earliest operation after which vertices ii and jj become connected, that is, after operation L(i,j)L(i,j).

After all mm operations, find the value of ∑i=1n∑j=i+1nL(i,j)\sum_{i=1}^n\sum_{j=i+1}^nL(i,j).

This is a basic application of disjoint-set union: maintain the size of each component and consider the contribution of every operation. If aia_i and bib_i belong to two different components during operation ii, merge the two components and add the product of their sizes multiplied by ii to the answer. The time complexity is O(nα(n))O(n\alpha(n)).

B

B

There are nn vertices, all isolated initially.

Next, there are mm edge-addition operations. Operation ii adds an undirected edge between aia_i and bib_i.

Next, there are qq queries. In query ii, determine after which operation vertices uiu_i and viv_i first become connected.

When merging components in disjoint-set union, maintain a “disjoint-set union spanning tree”: if aia_i and bib_i belong to different components during operation ii, include the edge (ai,bi)(a_i,b_i) in the spanning tree, with edge weight ii. A query then asks for the maximum edge weight on the path from uu to vv, which can be maintained using binary lifting or heavy-light decomposition. The time complexity is O(nlog⁡n)O(n\log n).

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 nn vertices, all isolated initially.

Next, there are mm edge-addition operations. Operation ii adds an undirected edge between aia_i and bib_i.

Next, there are qq queries. In query ii, determine the size of the connected component containing vertex xix_i after operation tit_i.

Offline algorithm: sort the queries in increasing order of tit_i. Process the queries while adding edges with a disjoint-set union. The time complexity is O(qlog⁡q+(n+q)α(n))O(q\log q+(n+q)\alpha(n)).

Online algorithm: the online algorithm for this problem can use only a Kruskal reconstruction tree. The difference from disjoint-set union is that, when aia_i and bib_i belong to different components during operation ii, Kruskal creates a new vertex uu, then connects the roots of the components containing aia_i and bib_i to uu as uu's two children. Let the vertex weight of uu be ii. The initial nn vertices have vertex weight 00.

For a query, we only need to find the largest connected component containing xix_i in the reconstruction tree such that the maximum vertex weight in the component does not exceed tit_i. The answer is the number of vertices in this component whose vertex weight is 00, 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 xix_i to the root, we can use binary lifting to find the vertex with the largest weight not exceeding tit_i. This gives the answer. The time complexity is O(nlog⁡n)O(n\log n).

D

D

Given a binary sequence a1,…,ana_1,\ldots,a_n of length nn, initially all 00, perform mm operations:

  • Set ax=1a_x=1.
  • Find the leftmost position whose value is 00 among ax,ax+1,…,ana_x,a_{x+1},\ldots,a_n.

Maintain a disjoint-set union where fif_i is the position of the first 00 among ai,ai+1,…,ana_i,a_{i+1},\ldots,a_n. Initially, fi=if_i=i.

For an operation setting ax=1a_x=1, do nothing if axa_x was already 11; otherwise, set fx=fx+1f_x=f_{x+1}.

The time complexity is O(nlog⁡n)O(n\log n). Using union by rank is somewhat cumbersome to implement, but it is still possible; in that case, the time complexity can be O(nα(n))O(n\alpha(n)).

E

E

Given three sequences aa, bb, and cc of positive integers of length nn, enumerate 1≤i≤j≤n1\le i\le j\le n and find the maximum value of ai⋅bj⋅min⁡i≤k≤jcka_i\cdot b_j\cdot \min_{i\le k\le j}c_k.

There are also many ways to solve this problem; here we focus on the disjoint-set union approach. Consider ckc_k in decreasing order of value. Equivalently, add a vertex at position kk, then merge it with the components containing positions k−1k-1 and k+1k+1 if those positions already contain vertices. Store the maximum value of aa and the maximum value of bb in each component, and update the answer during merges. The time complexity is O(nlog⁡n)O(n\log n).

F

F

Given a tree with nn vertices, perform mm operations:

  • Add an edge from aia_i to bib_i.
  • Ask whether there are at least two edge-disjoint paths between uiu_i and viv_i.

The query can be transformed into asking whether uiu_i and viv_i lie on the same simple cycle. Following the idea of contracting biconnected components, whenever an edge is added between aia_i and bib_i, contract all vertices on the tree path from aia_i to bib_i. If the tree paths corresponding to two added edges (ai,bi)(a_i,b_i) and (aj,bj)(a_j,b_j) 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 aia_i to bib_i once. The query becomes checking whether there is an uncovered edge on the path from uiu_i to viv_i. If there is none, then uiu_i and viv_i 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 fif_i be the first uncovered edge on the path from ii to the root. For each edge-addition operation, repeatedly jump using disjoint-set union. After covering an edge, merge the ff of the corresponding vertex with its parent. Each edge is covered at most once, so the total complexity is O(nlog⁡n)O(n\log n). Union by rank can likewise achieve O(nα(n))O(n\alpha(n)).

The maintenance method is similar to the tree version of D.

G

G

An undirected graph GG has nn vertices, all isolated initially (that is, it has no edges).

Next, there are mm edge-addition operations. Operation ii adds an undirected edge between aia_i and bib_i.

After every operation, find the number of bridges in the graph.

An edge (x,y)(x,y) in GG is called a bridge if deleting it increases the number of connected components; then (x,y)(x,y) 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 pip_i denote the parent of vertex ii; this is disjoint-set union without path compression.

If, during operation ii, aia_i and bib_i belong to the same connected component, contract the vertices on the path between aia_i and bib_i in the bridge tree, which can be maintained with disjoint-set union. Each contraction decreases the number of biconnected components by 11, and there can be at most n−1n-1 contractions, so the disjoint-set union complexity of the contraction part is O(nα(n))O(n\alpha(n)).

To contract the path, first find the LCA of aia_i and bib_i in the bridge tree. Maintain a marker array. Starting from aia_i and bib_i, 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 aia_i and bib_i. The complexity is linear in the length of the path from aia_i to bib_i, which is acceptable.

If aia_i and bib_i belong to different connected components, merge the two components and increase the number of bridges by 11. We must connect the two bridge trees by adding an edge from aia_i to bib_i. 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 O(nlog⁡n)O(n\log n).

Therefore, the total complexity of the algorithm is O(nlog⁡n+mlog⁡n)O(n\log n+m\log n).

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.

This content comes from OI Wiki: Applications of Disjoint-Set Union. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.