competitive_library/structure/
disjoint_set_union_undo.rs1use std::collections::{HashMap, HashSet, VecDeque};
3#[derive(Debug, Clone)]
4enum Node {
5 Root(usize, usize),
6 Child(usize),
7}
8#[derive(Clone, Debug)]
11pub struct DisjointSetUnionRollback {
12 uf: Vec<Node>,
13 history: VecDeque<(usize, Node)>,
14 restore_point: Option<usize>,
15}
16
17impl DisjointSetUnionRollback {
18 #[inline]
20 pub fn new(n: usize) -> DisjointSetUnionRollback {
21 DisjointSetUnionRollback {
22 uf: vec![Node::Root(1, 1); n],
23 history: VecDeque::new(),
24 restore_point: None,
25 }
26 }
27
28 #[inline]
31 pub fn root(&self, target: usize) -> usize {
32 match self.uf[target] {
33 Node::Root(_, _) => target,
34 Node::Child(par) => self.root(par),
35 }
36 }
37
38 #[inline]
42 pub fn unite(&mut self, x: usize, y: usize) -> bool {
43 let rx = self.root(x);
44 let ry = self.root(y);
45 if rx == ry {
46 return false;
47 }
48 self.history.push_back((rx, self.uf[rx].clone()));
49 self.history.push_back((ry, self.uf[ry].clone()));
50 let size_x = self.size(rx);
51 let size_y = self.size(ry);
52 let rank_x = self.rank(rx);
53 let rank_y = self.rank(ry);
54 let (i, j) = if rank_x > rank_y { (rx, ry) } else { (ry, rx) };
55 self.uf[i] = Node::Root(
56 size_x + size_y,
57 (rank_x.min(rank_y) + 1).max(rank_x.max(rank_y)),
58 );
59 self.uf[j] = Node::Child(i);
60
61 true
62 }
63
64 #[inline]
66 pub fn is_same(&mut self, x: usize, y: usize) -> bool {
67 self.root(x) == self.root(y)
68 }
69
70 pub fn size(&mut self, x: usize) -> usize {
72 let root = self.root(x);
73 match self.uf[root] {
74 Node::Root(size, _) => size,
75 Node::Child(_) => 1,
76 }
77 }
78 #[inline]
80 pub fn rank(&mut self, x: usize) -> usize {
81 let root = self.root(x);
82 match self.uf[root] {
83 Node::Root(_, rank) => rank,
84 Node::Child(_) => 1,
85 }
86 }
87
88 #[inline]
90 pub fn undo(&mut self) {
91 for _ in 0..2 {
92 let (index, node) = self.history.pop_back().unwrap();
93 self.uf[index] = node;
94 }
95 }
96
97 #[inline]
100 pub fn snapshot(&mut self) {
101 self.restore_point = Some(self.history.len() >> 1);
102 }
103
104 #[inline]
106 pub fn get_history_length(&self) -> usize {
107 self.history.len() >> 1
108 }
109
110 #[inline]
112 pub fn rollback_snapshot(&mut self) {
113 self.rollback(self.restore_point.unwrap());
114 }
115
116 #[inline]
119 pub fn rollback(&mut self, n: usize) {
120 assert!(self.history.len() >= n << 1);
121
122 while self.history.len() > n << 1 {
123 self.undo();
124 }
125 }
126
127 #[inline]
129 pub fn get_same_group(&mut self, x: usize) -> HashSet<usize> {
130 let root = self.root(x);
131 let mut g = HashSet::new();
132 for i in 0..self.uf.len() {
133 if root == self.root(i) {
134 g.insert(i);
135 }
136 }
137 g
138 }
139
140 #[inline]
142 pub fn get_all_groups(&mut self) -> HashMap<usize, HashSet<usize>> {
143 let mut map: HashMap<usize, HashSet<usize>> = HashMap::new();
144 for i in 0..self.uf.len() {
145 let root = self.root(i);
146
147 map.entry(root).or_default().insert(i);
148 }
149 map
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156
157 #[test]
158 fn test_dsu_rollback() {
159 let mut dsu = DisjointSetUnionRollback::new(6);
160
161 dsu.unite(0, 1);
162 assert!(dsu.is_same(0, 1));
163 dsu.unite(1, 2);
164 assert!(dsu.is_same(0, 2));
165 assert_eq!(dsu.size(0), 3);
166 assert!(!dsu.is_same(0, 3));
167 dsu.snapshot();
168 dsu.unite(0, 3);
169 dsu.unite(3, 4);
170 dsu.unite(4, 5);
171 assert_eq!(dsu.size(5), 6);
172 assert!(dsu.is_same(0, 5));
173 dsu.undo();
174 assert!(!dsu.is_same(0, 5));
175 dsu.rollback_snapshot();
176 assert!(dsu.is_same(0, 2));
177 assert_eq!(dsu.size(0), 3);
178 assert!(!dsu.is_same(0, 3));
179 dsu.rollback(0);
180 assert!(!dsu.is_same(0, 1));
181 assert_eq!(dsu.get_history_length(), 0);
182 }
183}