fn decompose_tree(t: &Graph, root: usize) -> (usize, Graph) {
let n = t.head.len();
let mut result = Graph::new(n, n - 1);
let mut stack = Graph::new(64 - n.leading_zeros() as usize, n);
let mut extract_chain = |stack: &mut Graph, mut labels: u32, mut u: usize| {
while labels != 0 {
let label = labels.ilog2();
labels ^= 1 << label;
let back = stack.head[label as usize];
let (next, v) = stack.link[back as usize];
stack.head[label as usize] = next;
result.connect(u, v as usize);
u = v as usize;
}
};
let mut forbidden = vec![0; n];
let mut dfs = vec![(root as u32, u32::MAX, t.head[root], 0u32, 0u32)];
let mut last_f = 0;
while let Some((u, pu, eu, f1, f2)) = dfs.last_mut() {
if let Some(&(ev, v)) = t.link.get(*eu as usize) {
let now = *eu;
*eu = ev;
if now == *pu {
continue;
}
dfs.push((v, now ^ 1, t.head[v as usize], 0, 0));
} else {
let fu = (*f1 | ((1 << (*f2 * 2 + 1).ilog2()) - 1)) + 1;
forbidden[*u as usize] = fu;
last_f = fu;
let lu = fu.trailing_zeros();
stack.connect(lu as usize, *u as usize);
for (_, v) in t.neighbor(*u as usize) {
extract_chain(&mut stack, forbidden[v] & ((1 << lu) - 1), *u as usize);
}
dfs.pop();
let fv = fu;
if let Some((_, _, _, f1, f2)) = dfs.last_mut() {
*f2 |= *f1 & fv;
*f1 |= fv;
}
}
}
let maxl = last_f.ilog2() as usize;
let back = stack.head[maxl];
let (next, root) = stack.link[back as usize];
stack.head[maxl] = next;
extract_chain(&mut stack, last_f & ((1 << maxl) - 1), root as usize);
(root as usize, result)
}