Skip to main content

union_find/
lib.rs

1//! Generic Union-Find (Disjoint Set) data structure.
2//!
3//! Each component carries:
4//! - a `size` (used for union-by-size),
5//! - a `character` value (an arbitrary `usize` updated through the user-supplied `op` closure).
6//!
7//! `union(x, y, w)` merges the components of `x` and `y`, applying the closure
8//! `op` to combine their characters along with the edge weight `w`. When `x` and
9//! `y` are already in the same component, only `character[root] = op(character[root], w)`
10//! is updated and the function returns `false`; otherwise it returns `true`.
11
12/// Generic Union-Find with weighted union and per-component character.
13pub struct UnionFind<F>
14where
15    F: Fn(usize, usize) -> usize,
16{
17    root: Vec<usize>,
18    size: Vec<usize>,
19    components: usize,
20    character: Vec<usize>,
21    op: F,
22}
23
24impl<F> UnionFind<F>
25where
26    F: Fn(usize, usize) -> usize,
27{
28    /// Build a Union-Find over the indices `0..=n`. The closure `op` defines how
29    /// character values combine during `union`. `init` seeds every component's
30    /// character.
31    pub fn new(n: usize, op: F, init: usize) -> Self {
32        Self {
33            root: (0..=n).collect(),
34            size: vec![1; n + 1],
35            components: n,
36            character: vec![init; n + 1],
37            op,
38        }
39    }
40
41    /// Find the representative of `x` with path compression.
42    pub fn find(&mut self, x: usize) -> usize {
43        if self.root[x] == x {
44            return x;
45        }
46        self.root[x] = self.find(self.root[x]);
47        self.root[x]
48    }
49
50    /// Union the components of `x` and `y`, combining characters via `op` and `w`.
51    /// Returns `true` if a merge happened, `false` if `x` and `y` were already
52    /// in the same component.
53    pub fn union(&mut self, x: usize, y: usize, w: usize) -> bool {
54        let root_x = self.find(x);
55        let root_y = self.find(y);
56
57        if root_x == root_y {
58            self.character[root_x] = (self.op)(self.character[root_x], w);
59            return false;
60        }
61
62        if self.size[root_x] > self.size[root_y] {
63            self.size[root_x] += self.size[root_y];
64            self.character[root_x] =
65                (self.op)((self.op)(self.character[root_x], self.character[root_y]), w);
66            self.root[root_y] = root_x;
67        } else {
68            self.size[root_y] += self.size[root_x];
69            self.character[root_y] =
70                (self.op)((self.op)(self.character[root_x], self.character[root_y]), w);
71            self.root[root_x] = root_y;
72        }
73        self.components -= 1;
74        true
75    }
76
77    /// Whether `x` and `y` are in the same component.
78    pub fn are_connected(&mut self, x: usize, y: usize) -> bool {
79        self.find(x) == self.find(y)
80    }
81
82    /// Number of distinct components remaining.
83    pub fn get_components(&self) -> usize {
84        self.components
85    }
86
87    /// Representative of `x`.
88    pub fn get_root(&mut self, x: usize) -> usize {
89        self.find(x)
90    }
91
92    /// Character value associated with the component containing `x`.
93    pub fn get_character(&mut self, x: usize) -> usize {
94        let root_x = self.find(x);
95        self.character[root_x]
96    }
97
98    /// Size of the component containing `x`.
99    pub fn get_size(&mut self, x: usize) -> usize {
100        let root_x = self.find(x);
101        self.size[root_x]
102    }
103}