use crate::{
path::{FindMax, Path},
splay::Forest,
};
pub struct LinkCutTree<P: Path> {
forest: Forest<P>,
}
impl<P: Path> LinkCutTree<P> {
#[must_use]
pub fn new() -> Self {
Self {
forest: Forest::new(),
}
}
pub fn make_tree(&mut self, weight: f64) -> usize {
self.forest.create_node(weight)
}
#[must_use]
pub fn extend_forest(&mut self, weights: &[f64]) -> Vec<usize> {
weights
.iter()
.map(|&weight| self.make_tree(weight))
.collect()
}
pub fn remove_tree(&mut self, idx: usize) {
self.forest.delete_node(idx);
}
fn access(&mut self, v: usize) {
self.forest.splay(v);
self.forest.remove_preferred_child(v);
while let Some(path_idx) = self.forest.path_parent_of(v) {
self.forest.splay(path_idx);
self.forest.remove_preferred_child(path_idx);
self.forest.set_right(path_idx, v);
self.forest.splay(v); }
}
fn reroot(&mut self, v: usize) {
self.access(v);
self.forest.flip(v);
}
pub fn connected(&mut self, v: usize, w: usize) -> bool {
v == w || self.findroot(v) == self.findroot(w)
}
pub fn link(&mut self, v: usize, w: usize) -> bool {
self.reroot(v);
self.access(w);
if self.forest.parent_of(v).is_some() || v == w {
return false;
}
self.forest.set_left(v, w);
true
}
pub fn linked(&mut self, v: usize, w: usize) -> bool {
self.reroot(v);
self.access(w);
self.forest.left_of(w) == Some(v) && self.forest.right_of(v).is_none()
}
pub fn cut(&mut self, v: usize, w: usize) -> bool {
if !self.linked(v, w) {
return false;
}
self.forest.cut_left(w);
true
}
pub fn path(&mut self, v: usize, w: usize) -> P {
self.reroot(v);
self.access(w);
if self.forest.parent_of(v).is_none() && v != w {
return P::default(f64::INFINITY, usize::MAX);
}
self.forest.aggregated_path_of(w)
}
pub fn findroot(&mut self, v: usize) -> usize {
self.access(v);
let mut root = v;
while let Some(left) = self.forest.left_of(root) {
root = left;
}
self.forest.splay(root); root
}
}
impl Default for LinkCutTree<FindMax> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use crate::{FindSum, FindXor, LinkCutTree};
#[test]
pub fn link_cut() {
let mut lctree = super::LinkCutTree::default();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(0.0);
let c = lctree.make_tree(0.0);
let d = lctree.make_tree(0.0);
let e = lctree.make_tree(0.0);
let f = lctree.make_tree(0.0);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
let nodes = [a, b, c, d, e, f];
for i in nodes {
for j in nodes {
assert!(lctree.connected(i, j));
}
}
lctree.cut(e, a);
let left_tree = [a, b, c, d];
let right_tree = [e, f];
for i in left_tree {
for j in left_tree {
assert!(lctree.connected(i, j));
}
}
for i in right_tree {
for j in right_tree {
assert!(lctree.connected(i, j));
}
}
for left in left_tree {
for right in right_tree {
assert!(!lctree.connected(left, right));
}
}
}
#[test]
pub fn connected_so_no_need_to_link() {
let mut lctree = super::LinkCutTree::default();
let alice = lctree.make_tree(0.0);
let bob = lctree.make_tree(10.0);
let clay = lctree.make_tree(2.0);
lctree.link(alice, bob);
lctree.link(bob, clay);
assert!(!lctree.link(alice, clay));
}
#[test]
pub fn connected_but_no_edge_to_cut() {
let mut lctree = super::LinkCutTree::default();
let alice = lctree.make_tree(0.0);
let bob = lctree.make_tree(10.0);
let clay = lctree.make_tree(2.0);
lctree.link(alice, bob);
lctree.link(bob, clay);
assert!(!lctree.cut(alice, clay));
}
#[test]
pub fn linked() {
let mut lctree = super::LinkCutTree::default();
let alice = lctree.make_tree(0.0);
let bob = lctree.make_tree(0.0);
let clay = lctree.make_tree(0.0);
lctree.link(alice, bob);
lctree.link(bob, clay);
assert!(lctree.linked(alice, bob));
assert!(lctree.linked(bob, clay));
assert!(!lctree.linked(alice, clay));
}
#[test]
pub fn findroot() {
let mut lctree = super::LinkCutTree::default();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(0.0);
let c = lctree.make_tree(0.0);
let d = lctree.make_tree(0.0);
let e = lctree.make_tree(0.0);
let f = lctree.make_tree(0.0);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
let nodes = [a, b, c, d, e, f];
for i in nodes {
assert_eq!(lctree.findroot(i), a);
}
lctree.cut(e, a);
let left_tree = [a, b, c, d];
for i in left_tree {
assert_eq!(lctree.findroot(i), a);
}
let right_tree = [e, f];
for i in right_tree {
assert_eq!(lctree.findroot(i), e);
}
}
#[test]
pub fn reroot() {
let mut lctree = super::LinkCutTree::default();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(0.0);
let c = lctree.make_tree(0.0);
let d = lctree.make_tree(0.0);
let e = lctree.make_tree(0.0);
let f = lctree.make_tree(0.0);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
let nodes = [a, b, c, d, e, f];
for i in nodes {
assert_eq!(lctree.findroot(i), a);
}
lctree.reroot(b);
for i in nodes {
assert_eq!(lctree.findroot(i), b);
}
}
#[test]
pub fn findmax() {
let mut lctree = super::LinkCutTree::default();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(10.);
let c = lctree.make_tree(3.);
let d = lctree.make_tree(11.);
let e = lctree.make_tree(7.);
let f = lctree.make_tree(2.);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
assert_eq!(lctree.path(c, f).idx, b);
assert_eq!(lctree.path(d, f).idx, d);
assert_eq!(lctree.path(a, f).idx, e);
assert_eq!(lctree.path(a, a).idx, a);
}
#[test]
pub fn findxor() {
let mut lctree: LinkCutTree<FindXor> = super::LinkCutTree::new();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(10.);
let c = lctree.make_tree(3.);
let d = lctree.make_tree(11.);
let e = lctree.make_tree(7.);
let f = lctree.make_tree(2.);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
let result = lctree.path(c, f);
assert_eq!(result.xor, 3 ^ 10 ^ 0 ^ 7 ^ 2);
}
#[test]
pub fn findsum() {
let mut lctree: LinkCutTree<FindSum> = super::LinkCutTree::new();
let a = lctree.make_tree(0.0);
let b = lctree.make_tree(10.);
let c = lctree.make_tree(3.);
let d = lctree.make_tree(11.);
let e = lctree.make_tree(7.);
let f = lctree.make_tree(2.);
lctree.link(b, a);
lctree.link(c, b);
lctree.link(d, b);
lctree.link(e, a);
lctree.link(f, e);
assert_eq!(lctree.path(c, f).sum, 22.);
assert_eq!(lctree.path(d, f).sum, 30.);
assert_eq!(lctree.path(a, f).sum, 9.);
assert_eq!(lctree.path(a, a).sum, 0.);
assert_eq!(lctree.path(c, d).sum, 24.);
}
#[test]
pub fn test_extend_forest() {
let weights = vec![1.0, 2.0, 3.0];
let mut lctree = LinkCutTree::default();
let trees_ids = lctree.extend_forest(&weights);
assert_eq!(trees_ids, vec![0, 1, 2]);
}
#[test]
#[should_panic]
pub fn delete_tree() {
let mut lctree = LinkCutTree::default();
let alice = lctree.make_tree(0.0);
let bob = lctree.make_tree(1.0);
lctree.link(alice, bob);
lctree.remove_tree(alice); }
}