Skip to main content

incremental_tree_set_union/
static_tree.rs

1use alloc::vec;
2use alloc::vec::Vec;
3
4use crate::answer_table::{AnswerTable, encode_forest};
5use crate::macroset::Macroset;
6use crate::microset::{Microset, NO_PARENT, NodeInfo, microfind};
7
8/// Static tree set union data structure (Gabow-Tarjan Section 2).
9///
10/// The tree must be known in advance. Supports `link` and `find` operations
11/// in O(1) amortized time, with O(m + n) total for m operations on n nodes.
12///
13/// # Semantics
14///
15/// - Initially every node is its own **set name** (marked).
16/// - `link(v)` removes `v` as a set name, merging it into `parent(v)`'s set.
17///   After this, `find` will skip past `v`.
18/// - `find(v)` returns the nearest ancestor of `v` that is still a set name
19///   (has not been linked). A node is its own ancestor.
20/// - `link(root)` panics: the root has no parent.
21#[derive(Clone, Debug)]
22pub struct StaticTreeSetUnion {
23    node_info: Vec<NodeInfo>,
24    microsets: Vec<Microset>,
25    /// Flat array of all microset node IDs. Each microset's nodes are a
26    /// contiguous slice at `[offset..offset+len]`.
27    all_nodes: Vec<u32>,
28    answer_table: AnswerTable,
29    macroset: Macroset,
30    n: usize,
31}
32
33/// Return the children of node `v` in a CSR representation.
34#[inline]
35fn csr_children<'a>(v: usize, offsets: &[u32], children: &'a [u32]) -> &'a [u32] {
36    &children[offsets[v] as usize..offsets[v + 1] as usize]
37}
38
39impl StaticTreeSetUnion {
40    /// Construct from a parent array. `parents[i]` is the parent of node `i`.
41    /// The root node must satisfy `parents[root] == root`.
42    pub fn from_parents(parents: &[usize]) -> Self {
43        let n = parents.len();
44        assert!(n >= 1, "tree must have at least one node");
45
46        // Find root
47        let root = (0..n)
48            .find(|&i| parents[i] == i)
49            .expect("tree must have a root (parents[root] == root)");
50
51        // Build CSR children representation: 2 flat arrays, 0 extra heap allocs.
52        // Pass 1: count children per node
53        let mut degree = vec![0u32; n];
54        for (i, &p) in parents.iter().enumerate() {
55            if i != root {
56                degree[p] += 1;
57            }
58        }
59        // Pass 2: prefix sum for offsets
60        let mut offsets = vec![0u32; n + 1];
61        for i in 0..n {
62            offsets[i + 1] = offsets[i] + degree[i];
63        }
64        // Pass 3: fill children array
65        let num_edges = if n > 0 { n - 1 } else { 0 };
66        let mut children_flat = vec![0u32; num_edges];
67        let mut pos = offsets[..n].to_vec();
68        for (i, &p) in parents.iter().enumerate() {
69            if i != root {
70                children_flat[pos[p] as usize] = i as u32;
71                pos[p] += 1;
72            }
73        }
74
75        // Compute levels via BFS
76        let mut levels = vec![0u32; n];
77        let mut queue = vec![root];
78        let mut qi = 0;
79        while qi < queue.len() {
80            let v = queue[qi];
81            qi += 1;
82            for &c in csr_children(v, &offsets, &children_flat) {
83                levels[c as usize] = levels[v] + 1;
84                queue.push(c as usize);
85            }
86        }
87
88        // Build answer table
89        let answer_table = AnswerTable::new(n);
90        let b = answer_table.b;
91
92        // Initialize node_info
93        let mut node_info = vec![NodeInfo::default(); n];
94        for (i, &p) in parents.iter().enumerate() {
95            node_info[i].parent = if i == root { NO_PARENT } else { p as u32 };
96            node_info[i].level = levels[i];
97        }
98
99        // Track which nodes have been assigned to a microset
100        let mut assigned = vec![false; n];
101        let mut microsets_list: Vec<Microset> = Vec::new();
102        let mut all_nodes: Vec<u32> = Vec::with_capacity(n);
103        let mut d = vec![1u32; n];
104
105        // Non-recursive postorder traversal
106        let postorder = Self::postorder(root, &offsets, &children_flat);
107
108        // Threshold: d(v) < (b+1)/2. Use 2*d(v) < (b+1).
109        let threshold_2x = b + 1;
110
111        for &v in &postorder {
112            d[v] = 1;
113            let mut child_idx = 0;
114            let child_list = csr_children(v, &offsets, &children_flat);
115
116            loop {
117                while 2 * d[v] < threshold_2x && child_idx < child_list.len() {
118                    let w = child_list[child_idx] as usize;
119                    d[v] += d[w];
120                    child_idx += 1;
121                }
122
123                if 2 * d[v] < threshold_2x {
124                    break;
125                }
126
127                debug_assert!(child_idx > 0);
128
129                let split_children = &child_list[..child_idx];
130                Self::add_microset(
131                    v as u32,
132                    split_children,
133                    &offsets,
134                    &children_flat,
135                    &mut assigned,
136                    &mut node_info,
137                    &mut microsets_list,
138                    &mut all_nodes,
139                );
140
141                d[v] = 1;
142                if child_idx >= child_list.len() {
143                    break;
144                }
145            }
146        }
147
148        // Final microset: all remaining unassigned nodes (including root)
149        Self::add_final_microset(
150            root,
151            &offsets,
152            &children_flat,
153            &mut assigned,
154            &mut node_info,
155            &mut microsets_list,
156            &mut all_nodes,
157        );
158
159        // Initialize macrosets for all microset external roots
160        let mut macroset = Macroset::new(n);
161        for ms in &microsets_list {
162            if ms.root != NO_PARENT {
163                macroset.make_set(ms.root, node_info[ms.root as usize].level);
164            }
165        }
166
167        Self {
168            node_info,
169            microsets: microsets_list,
170            all_nodes,
171            answer_table,
172            macroset,
173            n,
174        }
175    }
176
177    fn postorder(root: usize, offsets: &[u32], children: &[u32]) -> Vec<usize> {
178        let mut result = Vec::new();
179        let mut stack: Vec<(usize, bool)> = vec![(root, false)];
180        while let Some((v, expanded)) = stack.pop() {
181            if expanded {
182                result.push(v);
183            } else {
184                stack.push((v, true));
185                for &c in csr_children(v, offsets, children).iter().rev() {
186                    stack.push((c as usize, false));
187                }
188            }
189        }
190        result
191    }
192
193    #[allow(clippy::too_many_arguments)]
194    fn add_microset(
195        ms_root: u32,
196        split_children: &[u32],
197        offsets: &[u32],
198        children: &[u32],
199        assigned: &mut [bool],
200        node_info: &mut [NodeInfo],
201        microsets: &mut Vec<Microset>,
202        all_nodes: &mut Vec<u32>,
203    ) {
204        let ms_id = microsets.len() as u32;
205        let nodes_offset = all_nodes.len() as u32;
206        let mut child_counts = [0u32; 16];
207        let mut count = 0usize;
208
209        let mut stack: Vec<u32> = Vec::new();
210        for &c in split_children.iter().rev() {
211            if !assigned[c as usize] {
212                stack.push(c);
213            }
214        }
215
216        while let Some(v) = stack.pop() {
217            debug_assert!(!assigned[v as usize]);
218            let idx = count;
219            all_nodes.push(v);
220            assigned[v as usize] = true;
221            node_info[v as usize].micro = ms_id;
222            node_info[v as usize].number = idx as u16;
223
224            let mut cc = 0u32;
225            for &child in csr_children(v as usize, offsets, children).iter().rev() {
226                if !assigned[child as usize] {
227                    stack.push(child);
228                    cc += 1;
229                }
230            }
231            child_counts[idx] = cc;
232            count += 1;
233        }
234
235        let forest = encode_forest(&child_counts, count);
236        microsets.push(Microset {
237            nodes_offset,
238            mark: 0,
239            forest,
240            root: ms_root,
241        });
242    }
243
244    fn add_final_microset(
245        root: usize,
246        offsets: &[u32],
247        children: &[u32],
248        assigned: &mut [bool],
249        node_info: &mut [NodeInfo],
250        microsets: &mut Vec<Microset>,
251        all_nodes: &mut Vec<u32>,
252    ) {
253        let ms_id = microsets.len() as u32;
254        let nodes_offset = all_nodes.len() as u32;
255        let mut child_counts = [0u32; 16];
256        let mut count = 0usize;
257
258        let mut stack = vec![root as u32];
259        while let Some(v) = stack.pop() {
260            debug_assert!(!assigned[v as usize]);
261            let idx = count;
262            all_nodes.push(v);
263            assigned[v as usize] = true;
264            node_info[v as usize].micro = ms_id;
265            node_info[v as usize].number = idx as u16;
266
267            let mut cc = 0u32;
268            for &child in csr_children(v as usize, offsets, children).iter().rev() {
269                if !assigned[child as usize] {
270                    stack.push(child);
271                    cc += 1;
272                }
273            }
274            if idx < 16 {
275                child_counts[idx] = cc;
276            }
277            count += 1;
278        }
279
280        let forest = encode_forest(&child_counts, count);
281        microsets.push(Microset {
282            nodes_offset,
283            mark: 0,
284            forest,
285            root: NO_PARENT,
286        });
287    }
288
289    /// Link node `v`: remove `v` as a set name, merging it into its
290    /// parent's set.
291    #[inline]
292    pub fn link(&mut self, v: usize) {
293        assert!(
294            self.node_info[v].parent != NO_PARENT,
295            "cannot link the root (it has no parent)"
296        );
297        let info = &self.node_info[v];
298        self.microsets[info.micro as usize].mark |= 1 << info.number;
299    }
300
301    /// Find the nearest ancestor of `v` that is still a set name
302    /// (has not been linked). A node is its own ancestor.
303    #[inline]
304    #[must_use]
305    pub fn find(&mut self, v: usize) -> usize {
306        let mut x = v as u32;
307        let mut y = microfind(
308            x,
309            &self.node_info,
310            &self.microsets,
311            &self.all_nodes,
312            &self.answer_table,
313        );
314
315        debug_assert_ne!(y, NO_PARENT, "root must always be a set name");
316
317        let x_micro = self.node_info[x as usize].micro;
318        let y_micro = self.node_info[y as usize].micro;
319
320        if x_micro != y_micro {
321            x = self.macroset.top(y);
322
323            loop {
324                y = microfind(
325                    x,
326                    &self.node_info,
327                    &self.microsets,
328                    &self.all_nodes,
329                    &self.answer_table,
330                );
331                debug_assert_ne!(y, NO_PARENT, "root must always be a set name");
332
333                let x_micro = self.node_info[x as usize].micro;
334                let y_micro = self.node_info[y as usize].micro;
335
336                if x_micro == y_micro {
337                    break;
338                }
339
340                // [GT83] corrected: MacroUnite(MicroFind(x), x)
341                self.macroset.unite(y, x);
342                x = self.macroset.top(y);
343            }
344        }
345
346        y as usize
347    }
348
349    #[must_use]
350    pub fn len(&self) -> usize {
351        self.n
352    }
353
354    #[must_use]
355    pub fn is_empty(&self) -> bool {
356        self.n == 0
357    }
358}