haar_lib/tree/
centroid_decomposition.rs1use crate::tree::*;
7
8#[derive(Clone)]
10pub struct Node {
11 pub par: Option<usize>,
13 pub children: Vec<usize>,
15 pub depth: usize,
17 pub subsize: usize,
19}
20
21pub struct CentroidDecomposition {
23 nodes: Vec<Node>,
24}
25
26impl CentroidDecomposition {
27 pub fn new<E: TreeEdgeTrait>(tree: &Tree<E>) -> Self {
29 let n = tree.len();
30 let mut this = Self {
31 nodes: vec![
32 Node {
33 par: None,
34 children: vec![],
35 depth: !0,
36 subsize: 0,
37 };
38 n
39 ],
40 };
41
42 let mut subsize = vec![0; n];
43 this.decompose(tree, 0, None, 0, &mut subsize);
44 for (a, s) in this.nodes.iter_mut().zip(subsize) {
45 a.subsize = s;
46 }
47 this
48 }
49
50 pub fn nodes(&self) -> &[Node] {
52 &self.nodes
53 }
54
55 fn decompose<E: TreeEdgeTrait>(
56 &mut self,
57 tree: &Tree<E>,
58 cur: usize,
59 par: Option<usize>,
60 d: usize,
61 subsize: &mut [usize],
62 ) {
63 self.dfs_subsize(tree, cur, None, subsize);
64 let c = self.get_centroid(tree, cur, None, subsize[cur], subsize);
65
66 self.nodes[c].par = par;
67 self.nodes[c].depth = d;
68
69 if let Some(par) = par {
70 self.nodes[par].children.push(c);
71 }
72
73 for e in tree.nodes[c].neighbors() {
74 if self.nodes[e.to()].depth != !0 {
75 continue;
76 }
77 self.decompose(tree, e.to(), Some(c), d + 1, subsize);
78 }
79 }
80
81 fn get_centroid<E: TreeEdgeTrait>(
82 &self,
83 tree: &Tree<E>,
84 cur: usize,
85 par: Option<usize>,
86 total_size: usize,
87 subsize: &[usize],
88 ) -> usize {
89 tree.nodes[cur]
90 .neighbors()
91 .filter(|e| par != Some(e.to()) && self.nodes[e.to()].depth == !0)
92 .find(|e| 2 * subsize[e.to()] > total_size)
93 .map_or(cur, |e| {
94 self.get_centroid(tree, e.to(), Some(cur), total_size, subsize)
95 })
96 }
97
98 fn dfs_subsize<E: TreeEdgeTrait>(
99 &self,
100 tree: &Tree<E>,
101 cur: usize,
102 par: Option<usize>,
103 subsize: &mut [usize],
104 ) {
105 subsize[cur] = 1 + tree.nodes[cur]
106 .neighbors()
107 .filter(|e| par != Some(e.to()) && self.nodes[e.to()].depth == !0)
108 .map(|e| {
109 self.dfs_subsize(tree, e.to(), Some(cur), subsize);
110 subsize[e.to()]
111 })
112 .sum::<usize>();
113 }
114}