Skip to main content

nekolib/ds/
union_find.rs

1//! union-find。
2
3use super::super::traits::disjoint_set;
4
5use std::cell::RefCell;
6
7use disjoint_set::DisjointSet;
8
9#[derive(Clone, Copy)]
10enum Item {
11    Parent(usize),
12    Size(usize),
13}
14
15/// union-find。
16///
17/// # Complexity
18/// |演算|時間計算量|
19/// |---|---|
20/// |`new`|$\\Theta(n)$|
21/// |`unite`|amortized $O(\\alpha(n))$|
22/// |`repr`|amortized $O(\\alpha(n))$|
23/// |`equiv`|amortized $O(\\alpha(n))$|
24/// |`count`|amortized $O(\\alpha(n))$|
25/// |`subset`|$\\Theta(n)$|
26///
27/// より tight には、$n$ 要素 $m$ クエリのとき、$O(m\\cdot\\alpha(m, n)+n)$ 時間となる。
28/// ただし、$\\alpha(m, n)$ は次のように定義される。
29/// $$ \\alpha(m, n) = \\min\\{k\\in\\mathbb{N}\\mid J\_k(\\lfloor\\log\_2(n)\\rfloor)\\le 1+m/n\\}. $$
30/// ここで、$g^\\diamond = (\\lceil{\\log\_2}\\rceil\\circ g)^\\star$ とし、$J\_0(r) =
31/// \\lceil(r-1)/2\\rceil$, $J\_k(r)=J\_{k-1}^\\diamond(r)$ ($k\\gt 0$) である。
32/// より直感的には、${\\underbrace{J\_0^{\\diamond\\diamond\\cdots\\diamond}}\_{k\\text{ many }\\diamond{\\text{s}}}}(\\lfloor\\log\_2(n)\\rfloor)$ が $1+m/n$ 以下になる最小の $k$ が $\\alpha(m, n)$ である。
33///
34///
35/// ## Complexity analysis
36///
37/// 参考文献ふたつめの PDF の概略を書く。`todo!()`
38///
39/// これらより、$f(m, n, r)\\le (\\alpha(m, n)+2)\\cdot m+2n$ が言える。
40///
41/// Note: $\\alpha\'(m, n) = \\min\\{k\\in\\mathbb{N}\\mid \\alpha\_k(n)\\le 3\\}$ として
42/// $\\alpha(m, n) = O(\\alpha\'(m, n))$ である。
43///
44///
45/// # Examples
46/// ```
47/// use nekolib::traits::DisjointSet;
48/// use nekolib::ds::UnionFind;
49///
50/// let mut uf = UnionFind::new(4);
51/// assert!(!uf.equiv(0, 2));
52/// uf.unite(0, 1);
53/// uf.unite(1, 2);
54/// assert!(uf.equiv(0, 2));
55/// assert!(!uf.equiv(0, 3));
56/// assert_eq!(uf.count(0), 3);
57/// ```
58///
59/// # References
60/// - <http://www.gabrielnivasch.org/fun/inverse-ackermann>
61/// - <http://cgi.di.uoa.gr/~ewcg06/invited/Seidel.pdf>
62#[derive(Clone)]
63pub struct UnionFind {
64    n: usize,
65    buf: RefCell<Vec<Item>>,
66}
67
68impl DisjointSet for UnionFind {
69    fn new(n: usize) -> Self {
70        Self { n, buf: RefCell::new(vec![Item::Size(1); n]) }
71    }
72    fn len(&self) -> usize { self.n }
73    fn unite(&mut self, u: usize, v: usize) -> bool {
74        let u = self.repr(u);
75        let v = self.repr(v);
76        if u == v {
77            return false;
78        }
79        let mut buf = self.buf.borrow_mut();
80        let (su, sv) = (buf[u], buf[v]);
81        match (su, sv) {
82            (Item::Size(su), Item::Size(sv)) => {
83                let (child, par) = if su < sv { (u, v) } else { (v, u) };
84                buf[par] = Item::Size(su + sv);
85                buf[child] = Item::Parent(par);
86            }
87            _ => unreachable!(),
88        }
89        true
90    }
91    fn repr(&self, mut u: usize) -> usize {
92        let mut res = u;
93        let mut buf = self.buf.borrow_mut();
94        while let Item::Parent(v) = buf[res] {
95            res = v;
96        }
97        let mut bu = buf[u];
98        while let Item::Parent(pu) = bu {
99            let tmp = pu;
100            buf[u] = Item::Parent(res);
101            u = tmp;
102            bu = buf[u];
103        }
104        res
105    }
106    fn count(&self, u: usize) -> usize {
107        let u = self.repr(u);
108        if let Item::Size(res) = self.buf.borrow()[u] {
109            res
110        } else {
111            unreachable!()
112        }
113    }
114}
115
116#[test]
117fn test() {
118    let n = 4;
119    let mut uf = UnionFind::new(n);
120    assert!(!uf.equiv(1, 3));
121    assert_eq!(uf.count(1), 1);
122    assert_eq!(uf.count(3), 1);
123    uf.unite(1, 3);
124    assert!(uf.equiv(1, 3));
125    assert_eq!(uf.count(1), 2);
126    assert_eq!(uf.count(3), 2);
127    uf.unite(2, 3);
128    assert!(uf.equiv(2, 3));
129    assert!(uf.equiv(1, 2));
130    assert!(!uf.equiv(1, 0));
131}