nekolib/ds/
potentialized_union_find.rs1use super::super::traits::binop;
4use super::super::traits::potential_function;
5
6use std::cell::RefCell;
7
8use binop::{CommutativeGroup, Magma};
9use potential_function::PotentialFunction;
10
11#[derive(Clone, Copy)]
12enum Item {
13 Parent(usize),
14 Size(usize),
15}
16
17#[derive(Clone)]
26pub struct PotentializedUnionFind<G: CommutativeGroup>
27where
28 <G as Magma>::Set: Clone,
29{
30 n: usize,
31 buf: RefCell<Vec<Item>>,
32 pot: RefCell<Vec<<G as Magma>::Set>>,
33 cgroup: G,
34}
35
36impl<G: CommutativeGroup> PotentialFunction for PotentializedUnionFind<G>
37where
38 <G as Magma>::Set: Clone,
39{
40 type Item = G;
41 fn new(n: usize, cgroup: G) -> Self {
42 Self {
43 n,
44 buf: RefCell::new(vec![Item::Size(1); n]),
45 pot: RefCell::new(vec![cgroup.id(); n]),
46 cgroup,
47 }
48 }
49
50 fn len(&self) -> usize { self.n }
51
52 fn relate(
53 &mut self,
54 u: usize,
55 v: usize,
56 w: G::Set,
57 ) -> Result<bool, G::Set> {
58 let ru = self.repr(u);
59 let rv = self.repr(v);
60 let mut buf = self.buf.borrow_mut();
61 let mut pot = self.pot.borrow_mut();
62 let diff =
64 self.cgroup.op(pot[v].clone(), self.cgroup.recip(pot[u].clone()));
65 if ru == rv {
66 let w_old = self.cgroup.recip(diff);
67 return if w == w_old { Ok(false) } else { Err(w_old) };
68 }
69 let w = self.cgroup.op(w, diff);
70
71 let (su, sv) = match (buf[ru], buf[rv]) {
72 (Item::Size(su), Item::Size(sv)) => (su, sv),
73 _ => unreachable!(),
74 };
75
76 let (child, par, d) =
77 if su < sv { (ru, rv, w) } else { (rv, ru, self.cgroup.recip(w)) };
78 buf[par] = Item::Size(su + sv);
79 buf[child] = Item::Parent(par);
80 pot[child] = d;
81 Ok(true)
82 }
83
84 fn diff(&self, u: usize, v: usize) -> Option<G::Set> {
85 if self.repr(u) != self.repr(v) {
86 return None;
87 }
88 let pot = self.pot.borrow();
89 Some(self.cgroup.op(pot[u].clone(), self.cgroup.recip(pot[v].clone())))
90 }
91
92 fn repr_diff(&self, u: usize) -> (usize, G::Set) {
93 let ru = self.repr(u);
94 (ru, self.pot.borrow()[u].clone())
95 }
96}
97
98impl<G: CommutativeGroup> PotentializedUnionFind<G>
99where
100 <G as Magma>::Set: Clone,
101{
102 pub fn with_len(n: usize) -> Self
103 where
104 G: Default,
105 {
106 Self::new(n, G::default())
107 }
108
109 fn repr(&self, mut u: usize) -> usize {
110 let mut res = u;
111 let mut buf = self.buf.borrow_mut();
112 let mut pot = self.pot.borrow_mut();
113 let mut p = self.cgroup.id();
114 while let Item::Parent(v) = buf[res] {
115 p = self.cgroup.op(p.clone(), pot[res].clone());
116 res = v;
117 }
118 let mut bu = buf[u];
119 while let Item::Parent(pu) = bu {
120 buf[u] = Item::Parent(res);
121 let tmp = p.clone();
122 p = self.cgroup.op(p.clone(), self.cgroup.recip(pot[u].clone()));
123 pot[u] = tmp;
124 u = pu;
125 bu = buf[u];
126 }
127 res
128 }
129}
130
131#[test]
132fn sanity_check() {
133 use binop::{
134 new_monoid, Associative, Commutative, Identity, Magma, PartialRecip,
135 Recip,
136 };
137
138 new_monoid! { OpXor = (u32, |x, y| x ^ y, 0, |x| x, +commutative) };
139
140 let mut uf = PotentializedUnionFind::<OpXor>::with_len(4);
141 assert_eq!(uf.relate(0, 1, 1), Ok(true));
142 assert_eq!(uf.relate(0, 2, 1), Ok(true));
143 assert_eq!(uf.relate(1, 2, 1), Err(0));
144 assert_eq!(uf.relate(1, 2, 0), Ok(false));
145
146 assert_ne!(uf.repr_diff(0).1, uf.repr_diff(1).1);
147 assert_ne!(uf.repr_diff(0).1, uf.repr_diff(2).1);
148 assert_eq!(uf.repr_diff(1).1, uf.repr_diff(2).1);
149 assert_eq!(uf.repr_diff(3), (3, 0));
150}