diff --git a/src/lib.rs b/src/lib.rs index 12f0633..811b784 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ mod node; mod path; mod splay; use path::update_max; +use splay::unflip; use crate::{ node::{Node, Parent}, @@ -52,9 +53,16 @@ impl LinkCutTree { update_max(&mut self.forest, v); } + /// Makes v the root of its represented tree by flipping the path from v to the root. + pub fn reroot(&mut self, v: usize) { + self.access(v); + self.forest[v].flipped ^= true; + unflip(&mut self.forest, v); + } + /// Creates a link between two nodes in the forest (where w is the parent of v). pub fn link(&mut self, v: usize, w: usize) { - self.access(v); + self.reroot(v); self.access(w); if !matches!(self.forest[v].parent, Parent::Root) || v == w { return; // already connected @@ -65,25 +73,31 @@ impl LinkCutTree { /// Checks if v and w are connected in the forest. pub fn connected(&mut self, v: usize, w: usize) -> bool { - self.access(v); // v is now the root of the tree + self.reroot(v); // v is now the root of the tree self.access(w); // if access(w) messed with the root of the tree, then v and w are connected: !matches!(self.forest[v].parent, Parent::Root) || v == w } - /// Cuts the link between v and its parent. - pub fn cut(&mut self, v: usize) { - self.access(v); - if let Some(left) = self.forest[v].left { + /// Cuts the link between nodes v and w (if it exists) + pub fn cut(&mut self, v: usize, w: usize) { + self.reroot(v); + self.access(w); + if matches!(self.forest[v].parent, Parent::Root) || v == w { + return; // not connected + } + // detach w from its parent (which is v) + if let Some(left) = self.forest[w].left { + self.forest[w].left = None; self.forest[left].parent = Parent::Root; - self.forest[v].left = None; } } - /// Finds the maximum weight in the path from v and the root of the tree that v is in. - pub fn findmax(&mut self, v: usize) -> usize { - self.access(v); - self.forest[v].max_weight_idx + /// Finds the maximum weight in the path from nodes v and w (if they are connected) + pub fn findmax(&mut self, v: usize, w: usize) -> usize { + self.reroot(v); + self.access(w); + self.forest[w].max_weight_idx } /// Finds the root of the tree that v is in. @@ -93,6 +107,7 @@ impl LinkCutTree { while let Some(left) = self.forest[root].left { root = left; } + splay(&mut self.forest, root); // fast access to the root next time root } } @@ -102,15 +117,7 @@ mod tests { use crate::node::Parent; #[test] - pub fn access_base_case() { - // access a single node, should do nothing - let mut tree = super::LinkCutTree::new(1); - tree.access(0); - assert!(matches!(tree.forest[0].parent, Parent::Root)); - } - - #[test] - pub fn access_leaf() { + pub fn access() { let mut tree = super::LinkCutTree::new(4); // '1' has a path pointer to '0', '1' has a right child '2'. // after access(2), '2' should be the root of the tree: @@ -134,23 +141,15 @@ mod tests { assert_eq!(tree.forest[1].right, None); } - #[test] - pub fn link_base_case() { - let mut tree = super::LinkCutTree::new(2); - assert!(!tree.connected(0, 1)); // not connected yet - tree.link(0, 1); - assert!(tree.connected(0, 1)); // now connected - } - #[test] pub fn link_already_connected() { // '2' has a right child '3': // link(0, 3) should add no link, and result in (| denotes a path pointer): - // 0 0 0 3 - // / \ / | / | / - // 1 2 => 1 2 => 1 3 => 0 - // \ \ / / \ - // 3 3 2 1 2 + // 0 3 + // / \ / + // 1 2 => 0 + // \ |\ + // 3 1 2 // let mut tree = super::LinkCutTree::new(4); tree.forest[0].left = Some(1); @@ -164,49 +163,14 @@ mod tests { assert_eq!(tree.forest[3].left, Some(0)); assert_eq!(tree.forest[3].right, None); assert!(matches!(tree.forest[0].parent, Parent::Node(3))); - assert_eq!(tree.forest[0].left, Some(1)); - assert_eq!(tree.forest[0].right, Some(2)); - assert!(matches!(tree.forest[1].parent, Parent::Node(0))); - assert_eq!(tree.forest[1].left, None); - assert_eq!(tree.forest[1].right, None); - assert!(matches!(tree.forest[2].parent, Parent::Node(0))); - assert_eq!(tree.forest[2].left, None); - assert_eq!(tree.forest[2].right, None); - } - - #[test] - pub fn link_already_connected_with_path() { - // '3' has a path pointer to '2', and '2' has a path pointer to '0': - // link(0, 3) should add no link, and result in (| denotes a path pointer): - // 0 0 0 3 - // / \ / | / | / - // 1 2 => 1 2 => 1 3 => 0 - // | | / / \ - // 3 3 2 1 2 - // - let mut tree = super::LinkCutTree::new(4); - tree.forest[0].left = Some(1); - tree.forest[0].right = Some(2); - tree.forest[1].parent = Parent::Node(0); - tree.forest[2].parent = Parent::Node(0); - tree.forest[3].parent = Parent::Path(2); - tree.link(0, 3); - assert!(matches!(tree.forest[3].parent, Parent::Root)); - assert_eq!(tree.forest[3].left, Some(0)); - assert_eq!(tree.forest[3].right, None); - assert!(matches!(tree.forest[0].parent, Parent::Node(3))); - assert_eq!(tree.forest[0].left, Some(1)); + assert_eq!(tree.forest[0].left, None); + assert!(matches!(tree.forest[1].parent, Parent::Path(0))); assert_eq!(tree.forest[0].right, Some(2)); - assert!(matches!(tree.forest[1].parent, Parent::Node(0))); - assert_eq!(tree.forest[1].left, None); - assert_eq!(tree.forest[1].right, None); assert!(matches!(tree.forest[2].parent, Parent::Node(0))); - assert_eq!(tree.forest[2].left, None); - assert_eq!(tree.forest[2].right, None); } #[test] - pub fn link_to_leftmost() { + pub fn link() { // Given two trees: // 0 3 // / \ @@ -234,27 +198,7 @@ mod tests { } #[test] - pub fn connected_with_root() { - // check three nodes, one is root: - // 0 - // / \ - // 1 2 - let mut tree = super::LinkCutTree::new(3); - tree.forest[0].left = Some(1); - tree.forest[0].right = Some(2); - tree.forest[1].parent = Parent::Node(0); - tree.forest[2].parent = Parent::Node(0); - - assert!(tree.connected(0, 1)); - assert!(tree.connected(0, 2)); - assert!(tree.connected(1, 2)); - assert!(tree.connected(0, 0)); - assert!(tree.connected(1, 1)); - assert!(tree.connected(2, 2)); - } - - #[test] - pub fn connected_with_path_pointers() { + pub fn connected() { // check two splay trees that are connected by a path pointer // 0 // / \ @@ -274,73 +218,7 @@ mod tests { } #[test] - pub fn cut_base_case() { - let mut tree = super::LinkCutTree::new(2); - assert!(!tree.connected(0, 1)); // not connected yet - - tree.link(0, 1); - // 0 - // / <= link(0, 1) - // 1 - assert!(matches!(tree.forest[0].parent, Parent::Root)); - assert_eq!(tree.forest[0].left, Some(1)); - assert_eq!(tree.forest[1].right, None); - assert!(matches!(tree.forest[1].parent, Parent::Node(0))); - - assert!(tree.connected(0, 1)); // now connected - assert!(matches!(tree.forest[1].parent, Parent::Root)); - assert_eq!(tree.forest[1].right, None); - assert_eq!(tree.forest[1].left, None); - assert!(matches!(tree.forest[0].parent, Parent::Path(1))); - - tree.cut(0); - assert!(matches!(tree.forest[1].parent, Parent::Root)); - assert_eq!(tree.forest[1].right, None); - // 0 0 - // / => - // 1 1 - assert!(!tree.connected(0, 1)); // now disconnected - } - - #[test] - pub fn cut_into_two_subtrees() { - let mut tree = super::LinkCutTree::new(5); - tree.forest[0].left = Some(1); - tree.forest[1].parent = Parent::Node(0); - tree.forest[1].left = Some(2); - tree.forest[2].parent = Parent::Node(1); - tree.forest[3].right = Some(4); - tree.forest[4].parent = Parent::Node(3); - // Given two trees: - // 0 3 - // / \ - // 1 4 - // / - // 2 - tree.link(2, 3); - // link(2, 3) should now result in: - // 2 - // / | - // 3 1 - // | \ - // 4 0 - assert!(matches!(tree.forest[2].parent, Parent::Root)); - assert_eq!(tree.forest[2].left, Some(3)); - assert_eq!(tree.forest[2].right, None); - assert_eq!(tree.forest[1].right, Some(0)); - assert!(matches!(tree.forest[3].parent, Parent::Node(2))); - assert_eq!(tree.forest[3].left, None); - assert_eq!(tree.forest[3].right, None); - assert!(matches!(tree.forest[4].parent, Parent::Path(3))); - - // We cut node 2 from its parent 3: - tree.cut(2); - assert!(!tree.connected(2, 3)); - assert!(!tree.connected(2, 4)); - } - - #[test] - pub fn connectivity() { + pub fn cut() { // We form a link-cut tree from a rooted tree with the following structure: // 0 // / \ @@ -370,7 +248,7 @@ mod tests { } // We cut node 6 from its parent 0: - lctree.cut(6); + lctree.cut(6, 0); // The forest should now look like this: // 0 @@ -401,54 +279,6 @@ mod tests { } } - #[test] - pub fn findmax() { - let mut lctree = super::LinkCutTree::new(10); - lctree.forest[0].weight = 4.0; - lctree.forest[1].weight = 2.0; - lctree.forest[2].weight = 6.0; - lctree.forest[3].weight = 3.0; - lctree.forest[4].weight = 9.0; - lctree.forest[5].weight = 5.0; - lctree.forest[6].weight = 0.0; - lctree.forest[7].weight = 7.0; - lctree.forest[8].weight = 1.0; - lctree.forest[9].weight = 8.0; - - // We form a link-cut tree from a rooted tree with the following structure - // (the numbers in parentheses are the weights of the nodes): - // 0(4) - // / \ - // 1(2) 5(5) - // / \ \ - // 2(6) 3(3) 6(0) - // / \ - // 4(9) 7(7) - // / \ - // 8(1) 9(8) - lctree.link(1, 0); - lctree.link(2, 1); - lctree.link(3, 1); - lctree.link(4, 2); - lctree.link(5, 0); - lctree.link(6, 5); - lctree.link(7, 6); - lctree.link(8, 7); - lctree.link(9, 7); - - // We check the node index with max weight in the path from each node to the root: - assert_eq!(lctree.findmax(0), 0); - assert_eq!(lctree.findmax(5), 5); - assert_eq!(lctree.findmax(1), 0); - assert_eq!(lctree.findmax(8), 7); - assert_eq!(lctree.findmax(2), 2); - assert_eq!(lctree.findmax(4), 4); - assert_eq!(lctree.findmax(7), 7); - assert_eq!(lctree.findmax(9), 9); - assert_eq!(lctree.findmax(3), 0); - assert_eq!(lctree.findmax(6), 5); - } - #[test] pub fn findroot() { // We form a link-cut tree from a rooted tree with the following structure: @@ -478,7 +308,7 @@ mod tests { } // We cut node 6 from its parent 0: - lctree.cut(6); + lctree.cut(6, 0); // the forest should now look like this: // 0 @@ -500,4 +330,31 @@ mod tests { assert_eq!(lctree.findroot(i), 6); } } + + #[test] + pub fn reroot() { + // We form a link-cut tree from a rooted tree with the following structure: + // 0 + // / \ + // 1 4 + // / \ + // 2 3 + let mut lctree = super::LinkCutTree::new(10); + lctree.link(1, 0); + lctree.link(2, 1); + lctree.link(3, 1); + lctree.link(4, 0); + + // Checking findroot (which should be 0 for all nodes): + for i in 0..5 { + assert_eq!(lctree.findroot(i), 0); + } + + // we make 1 the root of the tree: + lctree.reroot(1); + + for i in 0..5 { + assert_eq!(lctree.findroot(i), 1); + } + } } diff --git a/src/splay.rs b/src/splay.rs index 761b034..8cae991 100644 --- a/src/splay.rs +++ b/src/splay.rs @@ -8,10 +8,12 @@ use crate::{ /// # Panics /// Panics if `node_idx` is out of bounds or if `node_idx` does not have a right child. /// -/// # Examples: -/// 0 1 -/// \ => / -/// 1 0 +/// Example: +// 0 2 +// / \ => / \ +// 1 2 0 4 +// / \ / \ +// 3 4 1 3 fn rotate_left(forest: &mut [Node], node_idx: usize) { assert!( node_idx < forest.len(), @@ -50,10 +52,12 @@ fn rotate_left(forest: &mut [Node], node_idx: usize) { /// # Panics /// Panics if `node_idx` is out of bounds or if `node_idx` does not have a left child. /// -/// # Examples: -/// 0 1 -/// / => \ -/// 1 0 +// Example: +// 0 1 +// / \ => / \ +// 1 4 2 0 +// / \ / \ +// 2 3 3 4 fn rotate_right(forest: &mut [Node], node_idx: usize) { assert!( node_idx < forest.len(), @@ -91,11 +95,10 @@ fn rotate_right(forest: &mut [Node], node_idx: usize) { /// /// # Panics /// Panics if `node_idx` is out of bounds or if `node_idx` does not have a parent. -/// -/// # Examples: -/// 0 1 -/// / => \ -/// 1 0 +// Example: +// 0 1 +// / => \ +// 1 0 fn rotate(forest: &mut [Node], node_idx: usize) { assert!(node_idx < forest.len(), "rotate: node_idx out of bounds"); assert!( @@ -123,6 +126,12 @@ fn rotate(forest: &mut [Node], node_idx: usize) { /// 2 pub fn splay(forest: &mut [Node], node_idx: usize) { while let Parent::Node(parent_idx) = forest[node_idx].parent { + if let Parent::Node(grandparent_idx) = forest[parent_idx].parent { + unflip(forest, grandparent_idx); + } + unflip(forest, parent_idx); + unflip(forest, node_idx); + if let Parent::Node(grandparent_idx) = forest[parent_idx].parent { if (forest[grandparent_idx].left == Some(parent_idx)) == (forest[parent_idx].left == Some(node_idx)) @@ -140,11 +149,27 @@ pub fn splay(forest: &mut [Node], node_idx: usize) { rotate(forest, node_idx); } } + unflip(forest, node_idx); +} + +/// Unflips the subtree rooted at `node_idx`, swapping the left and right children. +/// The children's `flipped` flag is also toggled to propogate the change down the tree. +pub fn unflip(forest: &mut [Node], node_idx: usize) { + if forest[node_idx].flipped { + forest[node_idx].flipped = false; + std::mem::swap(&mut forest[node_idx].left, &mut forest[node_idx].right); + if let Some(left_child) = forest[node_idx].left { + forest[left_child].flipped ^= true; + } + if let Some(right_child) = forest[node_idx].right { + forest[right_child].flipped ^= true; + } + } } #[cfg(test)] mod tests { - use super::{rotate, rotate_left, rotate_right}; + use super::{rotate, rotate_left, rotate_right, unflip}; use crate::node::{self, Node}; fn create_nodes(n: usize) -> Vec { @@ -152,72 +177,69 @@ mod tests { } #[test] - #[should_panic] - pub fn rotate_left_single_node() { - // rotate left a single node, should panic: - let mut forest = create_nodes(1); - rotate_left(&mut forest, 0); - } - - #[test] - pub fn rotate_left_with_parent() { - // form the tree and rotate left on '0': - // 0 2 - // / \ => / - // 1 2 0 - // / - // 1 - let mut forest = create_nodes(3); + pub fn rotate_left_root() { + // form the following tree and rotate left on '0': + // 0 2 + // / \ => / \ + // 1 2 0 4 + // / \ / \ + // 3 4 1 3 + let mut forest = create_nodes(5); forest[0].left = Some(1); forest[0].right = Some(2); forest[1].parent = node::Parent::Node(0); forest[2].parent = node::Parent::Node(0); + forest[2].left = Some(3); + forest[2].right = Some(4); + forest[3].parent = node::Parent::Node(2); + forest[4].parent = node::Parent::Node(2); rotate_left(&mut forest, 0); assert!(matches!(forest[2].parent, node::Parent::Root)); assert_eq!(forest[2].left, Some(0)); - assert_eq!(forest[2].right, None); assert!(matches!(forest[0].parent, node::Parent::Node(2))); + assert_eq!(forest[2].right, Some(4)); + assert!(matches!(forest[4].parent, node::Parent::Node(2))); assert_eq!(forest[0].left, Some(1)); - assert_eq!(forest[0].right, None); assert!(matches!(forest[1].parent, node::Parent::Node(0))); + assert_eq!(forest[0].right, Some(3)); + assert!(matches!(forest[3].parent, node::Parent::Node(0))); assert!(forest[1].left.is_none()); assert!(forest[1].right.is_none()); + assert!(forest[3].left.is_none()); + assert!(forest[3].right.is_none()); } #[test] - #[should_panic] - pub fn rotate_right_single_node() { - // rotate right a single node, should panic: - let mut forest = create_nodes(1); - rotate_right(&mut forest, 0); - assert!(forest[0].left.is_none()); - assert!(forest[0].right.is_none()); - assert!(matches!(forest[0].parent, node::Parent::Root)); - } - - #[test] - pub fn rotate_right_with_parent() { + pub fn rotate_right_root() { // form the tree and rotate left on '0': - // 0 1 - // / \ => \ - // 1 2 0 - // \ - // 2 - let mut forest = create_nodes(3); + // 0 1 + // / \ => / \ + // 1 4 2 0 + // / \ / \ + // 2 3 3 4 + let mut forest = create_nodes(5); forest[0].left = Some(1); - forest[0].right = Some(2); + forest[0].right = Some(4); forest[1].parent = node::Parent::Node(0); - forest[2].parent = node::Parent::Node(0); + forest[4].parent = node::Parent::Node(0); + forest[1].left = Some(2); + forest[1].right = Some(3); + forest[2].parent = node::Parent::Node(1); + forest[3].parent = node::Parent::Node(1); rotate_right(&mut forest, 0); assert!(matches!(forest[1].parent, node::Parent::Root)); - assert_eq!(forest[1].left, None); + assert_eq!(forest[1].left, Some(2)); + assert!(matches!(forest[2].parent, node::Parent::Node(1))); assert_eq!(forest[1].right, Some(0)); assert!(matches!(forest[0].parent, node::Parent::Node(1))); - assert_eq!(forest[0].left, None); - assert_eq!(forest[0].right, Some(2)); - assert!(matches!(forest[2].parent, node::Parent::Node(0))); - assert!(forest[2].left.is_none()); - assert!(forest[2].right.is_none()); + assert_eq!(forest[0].left, Some(3)); + assert!(matches!(forest[3].parent, node::Parent::Node(0))); + assert_eq!(forest[0].right, Some(4)); + assert!(matches!(forest[4].parent, node::Parent::Node(0))); + assert!(forest[3].left.is_none()); + assert!(forest[3].right.is_none()); + assert!(forest[4].left.is_none()); + assert!(forest[4].right.is_none()); } #[test] @@ -256,16 +278,6 @@ mod tests { assert!(forest[0].right.is_none()); } - #[test] - pub fn splay_single_node() { - // splay a single node, should do nothing: - let mut forest = create_nodes(1); - super::splay(&mut forest, 0); - assert!(forest[0].left.is_none()); - assert!(forest[0].right.is_none()); - assert!(matches!(forest[0].parent, node::Parent::Root)); - } - #[test] pub fn splay_leaf() { // form the tree and splay on '2': @@ -350,4 +362,20 @@ mod tests { assert_eq!(forest[2].left, Some(3)); assert!(matches!(forest[3].parent, node::Parent::Node(2))); } + + #[test] + pub fn toggle_flip() { + let mut forest = create_nodes(3); + forest[0].left = Some(1); + forest[0].right = Some(2); + forest[1].parent = node::Parent::Node(0); + forest[2].parent = node::Parent::Node(0); + forest[0].flipped = true; + unflip(&mut forest, 0); + assert!(!forest[0].flipped); + assert!(forest[1].flipped); + assert!(forest[2].flipped); + assert_eq!(forest[0].left, Some(2)); + assert_eq!(forest[0].right, Some(1)); + } } diff --git a/tests/test_connectivity.rs b/tests/test_connectivity.rs index 562686d..48ed161 100644 --- a/tests/test_connectivity.rs +++ b/tests/test_connectivity.rs @@ -9,17 +9,6 @@ fn create_random_generator() -> StdRng { StdRng::seed_from_u64(seed) } -fn create_random_tree(rng: &mut StdRng) -> Vec<(usize, usize)> { - let mut nodes = Vec::from([0]); - let mut edges = Vec::new(); - for i in 1..NUMBER_OF_NODES { - let parent = nodes[rng.gen_range(0..i)]; - nodes.push(i); - edges.push((i, parent)); - } - edges -} - fn dfs( v: usize, adj: &Vec>, @@ -47,18 +36,16 @@ fn connected_components(edges: &HashSet<(usize, usize)>) -> Vec { // explore each component using dfs and assign component ids let mut visited = vec![false; NUMBER_OF_NODES]; let mut component_ids = vec![0; NUMBER_OF_NODES]; - let mut component_id = 0; for v in 0..NUMBER_OF_NODES { if !visited[v] { - component_id += 1; - dfs(v, &adj, &mut visited, &mut component_ids, component_id); + dfs(v, &adj, &mut visited, &mut component_ids, v); } } component_ids } const NUMBER_OF_NODES: usize = 100; -const NUMBER_OF_OPERATIONS: usize = 1000; +const NUMBER_OF_OPERATIONS: usize = 2000; #[derive(RandGen)] enum Operation { @@ -71,12 +58,11 @@ enum Operation { pub fn connectivity() { let now = std::time::Instant::now(); let mut rng = create_random_generator(); - let edges = create_random_tree(&mut rng); + let mut edges = HashSet::new(); // initialize link-cut tree, we start with a forest of single nodes // (edges are not added yet): let mut lctree = LinkCutTree::new(NUMBER_OF_NODES); - let mut edges_in_forest = HashSet::new(); let mut component_ids = (0..NUMBER_OF_NODES).collect::>(); // perform random operations: link, cut, or connected: @@ -84,28 +70,30 @@ pub fn connectivity() { let operation: Operation = rng.gen(); match operation { Operation::Link => { - let (v, w) = edges.iter().choose(&mut rng).unwrap(); - println!("Link {} {}", v, w); - lctree.link(*v, *w); + let v = rng.gen_range(0..NUMBER_OF_NODES); + let w = rng.gen_range(0..NUMBER_OF_NODES); + lctree.link(v, w); // ignores if v and w are already connected - edges_in_forest.insert((*v, *w)); - component_ids = connected_components(&edges_in_forest); + // We only add the edge if it connects two different trees, + // we don't want to create cycles: + if component_ids[v] != component_ids[w] { + edges.insert((v, w)); + component_ids = connected_components(&edges); + } } Operation::Cut => { - if edges_in_forest.is_empty() { + if edges.is_empty() { continue; } - let (v, w) = edges_in_forest.iter().choose(&mut rng).unwrap(); - println!("Cut {} {}", v, w); - lctree.cut(*v); + let (v, w) = edges.iter().choose(&mut rng).unwrap(); + lctree.cut(*v, *w); - edges_in_forest.remove(&(*v, *w)); - component_ids = connected_components(&edges_in_forest); + edges.remove(&(*v, *w)); + component_ids = connected_components(&edges); } Operation::Connected => { let v = rng.gen_range(0..NUMBER_OF_NODES); let w = rng.gen_range(0..NUMBER_OF_NODES); - println!("Connected {} {}", v, w); assert_eq!(lctree.connected(v, w), component_ids[v] == component_ids[w]); } } diff --git a/tests/test_findmax.rs b/tests/test_findmax.rs deleted file mode 100644 index d3f7f2e..0000000 --- a/tests/test_findmax.rs +++ /dev/null @@ -1,55 +0,0 @@ -use lctree::LinkCutTree; -use rand::{rngs::StdRng, seq::SliceRandom, Rng, SeedableRng}; - -fn create_random_generator() -> StdRng { - let seed = rand::thread_rng().gen(); - println!("Seed: {}", seed); // print seed so we can reproduce the test (if it fails). - StdRng::seed_from_u64(seed) -} - -fn create_random_tree(rng: &mut StdRng) -> (Vec<(usize, usize)>, Vec, Vec) { - let mut edges = Vec::new(); - let mut weights: Vec = (0..NUMBER_OF_NODES).map(|i| i as f64).collect(); - weights.shuffle(rng); - - let mut max_to_root = vec![0; NUMBER_OF_NODES]; - let mut in_tree = Vec::from([0]); - for i in 1..NUMBER_OF_NODES { - let parent_idx = rng.gen_range(0..in_tree.len()); - let parent = in_tree[parent_idx]; - edges.push((i, parent)); - - max_to_root[i] = if weights[i] > weights[max_to_root[parent]] { - i - } else { - max_to_root[parent] - }; - in_tree.push(i); - } - - (edges, weights, max_to_root) -} - -const NUMBER_OF_NODES: usize = 1000; - -#[test] -pub fn findmax_random() { - let mut rng = create_random_generator(); - let (edges, weights, expected_findmax) = create_random_tree(&mut rng); - - // initialize link-cut tree - let mut lctree = LinkCutTree::new(NUMBER_OF_NODES); - for i in 0..NUMBER_OF_NODES { - lctree.set_weight(i, weights[i]); - } - for (v, w) in edges { - lctree.link(v, w); - } - - // perform random findmax queries - let mut nodes = (0..NUMBER_OF_NODES).collect::>(); - nodes.shuffle(&mut rng); - for v in nodes { - assert_eq!(lctree.findmax(v), expected_findmax[v]); - } -}