centroid_decomposition/lib.rs
1//! Centroid Decomposition of a tree.
2//!
3//! Centroid decomposition recursively splits a tree at its centroid —
4//! the vertex whose removal leaves components of size at most `n/2` —
5//! and repeats on each component. The resulting recursion tree has
6//! height O(log n), and any two original vertices share an ancestor
7//! in the decomposition at depth at most O(log n).
8//!
9//! This is the foundation for "small-to-large" tricks on trees, for
10//! answering distance queries offline (count paths of length ≤ k), and
11//! for many divide-and-conquer-on-tree problems.
12//!
13//! This crate exposes [`build_centroid_tree`], which returns the
14//! centroid tree: for each vertex, the centroid chosen at the next
15//! level up (its "centroid parent") and the depth of the vertex in the
16//! centroid tree.
17//!
18//! # Example
19//!
20//! ```
21//! use centroid_decomposition::build_centroid_tree;
22//!
23//! // Path 0 -- 1 -- 2 -- 3 -- 4
24//! let adj = vec![
25//! vec![1],
26//! vec![0, 2],
27//! vec![1, 3],
28//! vec![2, 4],
29//! vec![3],
30//! ];
31//! let (parent, depth) = build_centroid_tree(&adj);
32//! // Centroid of a 5-path is the middle vertex (2).
33//! assert_eq!(parent[2], None);
34//! ```
35
36/// Build the centroid decomposition of the tree `adj`.
37///
38/// Returns two vectors of length `n`:
39/// * `parent[v]` — the centroid at the level above `v` in the
40/// decomposition (i.e., the centroid chosen for the component that
41/// contained `v` in the previous recursion step). `None` for the root
42/// of the centroid tree.
43/// * `depth[v]` — depth of `v` in the centroid tree (0 for the root).
44///
45/// # Panics
46/// Panics if `adj` is empty.
47pub fn build_centroid_tree(adj: &[Vec<usize>]) -> (Vec<Option<usize>>, Vec<usize>) {
48 let n = adj.len();
49 assert!(n > 0, "graph must be non-empty");
50
51 let mut parent: Vec<Option<usize>> = vec![None; n];
52 let mut depth = vec![0usize; n];
53 let mut removed = vec![false; n];
54 let mut size = vec![0usize; n];
55
56 decompose(adj, &mut removed, &mut size, 0, None, 0, &mut parent, &mut depth);
57
58 (parent, depth)
59}
60
61fn decompose(
62 adj: &[Vec<usize>],
63 removed: &mut [bool],
64 size: &mut [usize],
65 entry: usize,
66 centroid_parent: Option<usize>,
67 centroid_depth: usize,
68 parent: &mut [Option<usize>],
69 depth: &mut [usize],
70) {
71 // Compute subtree sizes within the current component, rooted at
72 // `entry`.
73 let root = entry;
74 compute_sizes(adj, removed, size, root, usize::MAX);
75 let total = size[root];
76
77 // Find centroid: a vertex `c` in the current component where every
78 // child component has size ≤ total/2.
79 let c = find_centroid(adj, removed, size, root, usize::MAX, total);
80
81 parent[c] = centroid_parent;
82 depth[c] = centroid_depth;
83 removed[c] = true;
84
85 // Recurse on each component formed by removing `c`.
86 for &u in &adj[c] {
87 if !removed[u] {
88 decompose(adj, removed, size, u, Some(c), centroid_depth + 1, parent, depth);
89 }
90 }
91 removed[c] = false;
92}
93
94fn compute_sizes(adj: &[Vec<usize>], removed: &[bool], size: &mut [usize], v: usize, p: usize) -> usize {
95 let mut s = 1usize;
96 for &u in &adj[v] {
97 if u != p && !removed[u] {
98 s += compute_sizes(adj, removed, size, u, v);
99 }
100 }
101 size[v] = s;
102 s
103}
104
105fn find_centroid(
106 adj: &[Vec<usize>],
107 removed: &[bool],
108 size: &[usize],
109 v: usize,
110 p: usize,
111 total: usize,
112) -> usize {
113 for &u in &adj[v] {
114 if u != p && !removed[u] && size[u] > total / 2 {
115 return find_centroid(adj, removed, size, u, v, total);
116 }
117 }
118 v
119}