use crate::{MinCutError, Result};
use std::collections::HashMap;
pub type NodeId = u64;
#[derive(Debug, Clone)]
struct XorShift64 {
state: u64,
}
impl XorShift64 {
#[inline]
fn new(seed: u64) -> Self {
Self {
state: if seed == 0 { 0x123456789abcdef0 } else { seed },
}
}
#[inline(always)]
fn next(&mut self) -> u64 {
self.state ^= self.state >> 12;
self.state ^= self.state << 25;
self.state ^= self.state >> 27;
self.state.wrapping_mul(0x2545f4914f6cdd1d)
}
}
#[derive(Debug, Clone)]
struct TreapNode {
vertex: NodeId,
priority: u64,
left: Option<usize>,
right: Option<usize>,
parent: Option<usize>,
size: usize,
value: f64,
subtree_aggregate: f64,
lazy_value: Option<f64>,
}
impl TreapNode {
#[inline]
fn new(vertex: NodeId, priority: u64, value: f64) -> Self {
Self {
vertex,
priority,
left: None,
right: None,
parent: None,
size: 1,
value,
subtree_aggregate: value,
lazy_value: None,
}
}
}
#[derive(Debug, Clone)]
pub struct EulerTourTree {
nodes: Vec<TreapNode>,
free_list: Vec<usize>,
first_occurrence: HashMap<NodeId, usize>,
last_occurrence: HashMap<NodeId, usize>,
edge_to_node: HashMap<(NodeId, NodeId), usize>,
enter_to_exit: HashMap<usize, usize>,
roots: HashMap<NodeId, usize>,
rng: XorShift64,
}
impl EulerTourTree {
#[inline]
pub fn new() -> Self {
Self::with_seed(42)
}
#[inline]
pub fn with_seed(seed: u64) -> Self {
Self::with_seed_and_capacity(seed, 16)
}
pub fn with_seed_and_capacity(seed: u64, capacity: usize) -> Self {
Self {
nodes: Vec::with_capacity(capacity),
free_list: Vec::with_capacity(capacity / 4),
first_occurrence: HashMap::with_capacity(capacity),
last_occurrence: HashMap::with_capacity(capacity),
edge_to_node: HashMap::with_capacity(capacity),
enter_to_exit: HashMap::with_capacity(capacity),
roots: HashMap::with_capacity(capacity),
rng: XorShift64::new(seed),
}
}
#[inline]
pub fn make_tree(&mut self, v: NodeId) -> Result<()> {
if self.first_occurrence.contains_key(&v) {
return Err(self.vertex_exists_error(v));
}
let priority = self.rng.next();
let idx = self.allocate_node(v, priority, 0.0);
self.first_occurrence.insert(v, idx);
self.last_occurrence.insert(v, idx);
self.roots.insert(v, idx);
Ok(())
}
#[cold]
#[inline(never)]
fn vertex_exists_error(&self, v: NodeId) -> MinCutError {
MinCutError::InternalError(format!("Vertex {} already exists in a tree", v))
}
pub fn link(&mut self, u: NodeId, v: NodeId) -> Result<()> {
let u_idx = *self
.first_occurrence
.get(&u)
.ok_or_else(|| MinCutError::InvalidVertex(u))?;
let v_root = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
if self.connected(u, v) {
return Err(MinCutError::EdgeExists(u, v));
}
self.reroot_internal(u)?;
let u_root = self.find_root_idx(u_idx)?;
let priority1 = self.rng.next();
let priority2 = self.rng.next();
let enter_v = self.allocate_node(v, priority1, 0.0);
let exit_v = self.allocate_node(u, priority2, 0.0);
self.edge_to_node.insert((u, v), enter_v);
self.enter_to_exit.insert(enter_v, exit_v);
let merged1 = self.merge(Some(u_root), Some(enter_v));
let merged2 = self.merge(merged1, Some(v_root));
let final_root = self.merge(merged2, Some(exit_v));
if let Some(root) = final_root {
let root_vertex = self.nodes[root].vertex;
self.update_root_mapping(root, root_vertex);
}
Ok(())
}
pub fn cut(&mut self, u: NodeId, v: NodeId) -> Result<()> {
let edge_node = self
.edge_to_node
.remove(&(u, v))
.or_else(|| self.edge_to_node.remove(&(v, u)))
.ok_or_else(|| MinCutError::EdgeNotFound(u, v))?;
self.reroot_internal(u)?;
let enter_v = edge_node;
let exit_u_idx = self.find_matching_exit(enter_v)?;
self.enter_to_exit.remove(&enter_v);
let pos1 = self.get_position(enter_v);
let pos2 = self.get_position(exit_u_idx);
let (start_pos, end_pos) = if pos1 < pos2 {
(pos1, pos2)
} else {
(pos2, pos1)
};
let root = self.find_root_idx(*self.first_occurrence.get(&u).unwrap())?;
let (left, rest) = self.split(root, start_pos);
if rest.is_none() {
return Err(MinCutError::InternalError("Split failed".to_string()));
}
let (enter_and_middle, right) = self.split(rest.unwrap(), end_pos - start_pos + 1);
let (enter_node, middle_and_exit) = self.split_first(enter_and_middle);
let (middle, exit_node) = self.split_last(middle_and_exit);
if let Some(idx) = enter_node {
self.free_node(idx);
}
if let Some(idx) = exit_node {
self.free_node(idx);
}
let u_tree = self.merge(left, right);
let v_tree = middle;
if let Some(root_idx) = u_tree {
let root_vertex = self.nodes[root_idx].vertex;
self.update_root_mapping(root_idx, root_vertex);
}
if let Some(root_idx) = v_tree {
let root_vertex = self.nodes[root_idx].vertex;
self.update_root_mapping(root_idx, root_vertex);
}
Ok(())
}
#[inline]
pub fn connected(&self, u: NodeId, v: NodeId) -> bool {
match (self.first_occurrence.get(&u), self.first_occurrence.get(&v)) {
(Some(&u_idx), Some(&v_idx)) => {
let u_root = self.find_root_idx(u_idx);
let v_root = self.find_root_idx(v_idx);
matches!((u_root, v_root), (Ok(ur), Ok(vr)) if ur == vr)
}
_ => false,
}
}
#[inline]
pub fn find_root(&self, v: NodeId) -> Result<NodeId> {
let v_idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
let root_idx = self.find_root_idx(v_idx)?;
Ok(self.nodes[root_idx].vertex)
}
#[inline]
pub fn tree_size(&self, v: NodeId) -> Result<usize> {
let v_idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
let root_idx = self.find_root_idx(v_idx)?;
let vertices = self.collect_vertices(root_idx);
Ok(vertices.len())
}
#[inline]
pub fn subtree_size(&self, v: NodeId) -> Result<usize> {
let first_idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
let last_idx = *self
.last_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
if first_idx == last_idx {
return Ok(1); }
let pos1 = self.get_position(first_idx);
let pos2 = self.get_position(last_idx);
let range_size = pos2.saturating_sub(pos1) + 1;
Ok((range_size + 1) / 2)
}
#[inline]
pub fn subtree_aggregate(&self, v: NodeId) -> Result<f64> {
let first_idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
Ok(self.nodes[first_idx].subtree_aggregate)
}
#[inline]
pub fn update_value(&mut self, v: NodeId, value: f64) -> Result<()> {
let first_idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
self.nodes[first_idx].value = value;
self.pull_up(first_idx);
Ok(())
}
pub fn reroot(&mut self, v: NodeId) -> Result<()> {
self.reroot_internal(v)
}
#[inline]
pub fn len(&self) -> usize {
self.first_occurrence.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.first_occurrence.is_empty()
}
pub fn bulk_make_trees(&mut self, vertices: &[NodeId]) -> Result<()> {
let count = vertices.len();
self.nodes.reserve(count);
self.first_occurrence.reserve(count);
self.last_occurrence.reserve(count);
self.roots.reserve(count);
for &v in vertices {
if self.first_occurrence.contains_key(&v) {
return Err(self.vertex_exists_error(v));
}
let priority = self.rng.next();
let idx = self.allocate_node(v, priority, 0.0);
self.first_occurrence.insert(v, idx);
self.last_occurrence.insert(v, idx);
self.roots.insert(v, idx);
}
Ok(())
}
pub fn bulk_update_values(&mut self, updates: &[(NodeId, f64)]) -> Result<()> {
let mut affected_indices = Vec::with_capacity(updates.len());
for &(v, value) in updates {
let idx = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
self.nodes[idx].lazy_value = Some(value);
affected_indices.push(idx);
}
for &idx in &affected_indices {
self.push_down_lazy(idx);
self.pull_up(idx);
}
Ok(())
}
pub fn bulk_link(&mut self, edges: &[(NodeId, NodeId)]) -> Result<()> {
for &(u, v) in edges {
self.first_occurrence
.get(&u)
.ok_or_else(|| MinCutError::InvalidVertex(u))?;
self.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
}
for &(u, v) in edges {
self.link(u, v)?;
}
Ok(())
}
#[inline]
fn find_root_idx(&self, mut idx: usize) -> Result<usize> {
let mut visited = 0;
let max_depth = self.nodes.len() * 2;
while let Some(parent) = self.nodes[idx].parent {
idx = parent;
visited += 1;
if visited > max_depth {
return Err(MinCutError::InternalError(
"Cycle detected in tree".to_string(),
));
}
}
Ok(idx)
}
fn reroot_internal(&mut self, v: NodeId) -> Result<()> {
let v_first = *self
.first_occurrence
.get(&v)
.ok_or_else(|| MinCutError::InvalidVertex(v))?;
let root = self.find_root_idx(v_first)?;
let pos = self.get_position(v_first);
if pos == 0 {
return Ok(());
}
let (left, right) = self.split(root, pos);
let new_root = self.merge(right, left);
if let Some(root_idx) = new_root {
let root_vertex = self.nodes[root_idx].vertex;
self.update_root_mapping(root_idx, root_vertex);
}
Ok(())
}
fn update_root_mapping(&mut self, root_idx: usize, _root_vertex: NodeId) {
let vertices = self.collect_vertices(root_idx);
for vertex in vertices {
self.roots.insert(vertex, root_idx);
}
}
fn collect_vertices(&self, idx: usize) -> Vec<NodeId> {
let estimated_size = self.nodes[idx].size / 2;
let mut vertices = Vec::with_capacity(estimated_size);
let mut visited = std::collections::HashSet::with_capacity(estimated_size);
self.collect_vertices_helper(idx, &mut vertices, &mut visited);
vertices
}
#[inline]
fn collect_vertices_helper(
&self,
idx: usize,
vertices: &mut Vec<NodeId>,
visited: &mut std::collections::HashSet<NodeId>,
) {
let node = &self.nodes[idx];
if visited.insert(node.vertex) {
vertices.push(node.vertex);
}
if let Some(left) = node.left {
self.collect_vertices_helper(left, vertices, visited);
}
if let Some(right) = node.right {
self.collect_vertices_helper(right, vertices, visited);
}
}
#[inline]
fn find_matching_exit(&self, enter_idx: usize) -> Result<usize> {
self.enter_to_exit.get(&enter_idx).copied().ok_or_else(|| {
MinCutError::InternalError(format!(
"No matching exit node found for enter index {}",
enter_idx
))
})
}
#[inline]
fn split(&mut self, root: usize, pos: usize) -> (Option<usize>, Option<usize>) {
if pos == 0 {
return (None, Some(root));
}
self.push_down_lazy(root);
let left_size = self.nodes[root]
.left
.map(|l| self.nodes[l].size)
.unwrap_or(0);
if pos <= left_size {
if let Some(left_child) = self.nodes[root].left {
let (split_left, split_right) = self.split(left_child, pos);
self.nodes[root].left = split_right;
if let Some(idx) = split_right {
self.nodes[idx].parent = Some(root);
}
self.pull_up(root);
if let Some(idx) = split_left {
self.nodes[idx].parent = None;
}
(split_left, Some(root))
} else {
(None, Some(root))
}
} else {
let right_pos = pos - left_size - 1;
if let Some(right_child) = self.nodes[root].right {
let (split_left, split_right) = self.split(right_child, right_pos);
self.nodes[root].right = split_left;
if let Some(idx) = split_left {
self.nodes[idx].parent = Some(root);
}
self.pull_up(root);
if let Some(idx) = split_right {
self.nodes[idx].parent = None;
}
(Some(root), split_right)
} else {
(Some(root), None)
}
}
}
#[inline]
fn merge(&mut self, left: Option<usize>, right: Option<usize>) -> Option<usize> {
match (left, right) {
(None, right) => right,
(left, None) => left,
(Some(l), Some(r)) => {
self.push_down_lazy(l);
self.push_down_lazy(r);
if self.nodes[l].priority > self.nodes[r].priority {
let new_right = self.merge(self.nodes[l].right, Some(r));
self.nodes[l].right = new_right;
if let Some(idx) = new_right {
self.nodes[idx].parent = Some(l);
}
self.nodes[l].parent = None;
self.pull_up(l);
Some(l)
} else {
let new_left = self.merge(Some(l), self.nodes[r].left);
self.nodes[r].left = new_left;
if let Some(idx) = new_left {
self.nodes[idx].parent = Some(r);
}
self.nodes[r].parent = None;
self.pull_up(r);
Some(r)
}
}
}
}
#[inline]
fn split_first(&mut self, root: Option<usize>) -> (Option<usize>, Option<usize>) {
match root {
None => (None, None),
Some(idx) => {
let (first, rest) = self.split(idx, 1);
(first, rest)
}
}
}
#[inline]
fn split_last(&mut self, root: Option<usize>) -> (Option<usize>, Option<usize>) {
match root {
None => (None, None),
Some(idx) => {
let size = self.nodes[idx].size;
if size == 0 {
return (None, None);
}
let (rest, last) = self.split(idx, size - 1);
(rest, last)
}
}
}
#[inline]
fn allocate_node(&mut self, vertex: NodeId, priority: u64, value: f64) -> usize {
if let Some(idx) = self.free_list.pop() {
self.nodes[idx] = TreapNode::new(vertex, priority, value);
idx
} else {
let idx = self.nodes.len();
self.nodes.push(TreapNode::new(vertex, priority, value));
idx
}
}
#[inline]
fn free_node(&mut self, idx: usize) {
self.nodes[idx].left = None;
self.nodes[idx].right = None;
self.nodes[idx].parent = None;
self.nodes[idx].lazy_value = None;
self.free_list.push(idx);
}
#[inline(always)]
fn push_down_lazy(&mut self, idx: usize) {
if let Some(lazy_val) = self.nodes[idx].lazy_value.take() {
self.nodes[idx].value = lazy_val;
if let Some(left) = self.nodes[idx].left {
self.nodes[left].lazy_value = Some(lazy_val);
}
if let Some(right) = self.nodes[idx].right {
self.nodes[right].lazy_value = Some(lazy_val);
}
self.pull_up(idx);
}
}
#[inline(always)]
fn pull_up(&mut self, idx: usize) {
let mut size = 1;
let mut aggregate = self.nodes[idx].value;
if let Some(left) = self.nodes[idx].left {
size += self.nodes[left].size;
aggregate += self.nodes[left].subtree_aggregate;
}
if let Some(right) = self.nodes[idx].right {
size += self.nodes[right].size;
aggregate += self.nodes[right].subtree_aggregate;
}
self.nodes[idx].size = size;
self.nodes[idx].subtree_aggregate = aggregate;
}
#[inline]
fn get_position(&self, idx: usize) -> usize {
let mut pos = self.nodes[idx]
.left
.map(|l| self.nodes[l].size)
.unwrap_or(0);
let mut current = idx;
while let Some(parent) = self.nodes[current].parent {
if self.nodes[parent].right == Some(current) {
pos += 1;
if let Some(left) = self.nodes[parent].left {
pos += self.nodes[left].size;
}
}
current = parent;
}
pos
}
}
impl Default for EulerTourTree {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_make_tree() {
let mut ett = EulerTourTree::new();
assert!(ett.make_tree(1).is_ok());
assert!(ett.make_tree(2).is_ok());
assert_eq!(ett.len(), 2);
}
#[test]
fn test_singleton_tree() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
assert_eq!(ett.tree_size(1).unwrap(), 1);
assert_eq!(ett.subtree_size(1).unwrap(), 1);
assert!(ett.connected(1, 1));
}
#[test]
fn test_link_two_vertices() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
assert!(!ett.connected(1, 2));
ett.link(1, 2).unwrap();
assert!(ett.connected(1, 2));
assert_eq!(ett.tree_size(1).unwrap(), 2);
assert_eq!(ett.tree_size(2).unwrap(), 2);
}
#[test]
fn test_link_multiple_vertices() {
let mut ett = EulerTourTree::new();
for i in 1..=5 {
ett.make_tree(i).unwrap();
}
ett.link(1, 2).unwrap();
ett.link(2, 3).unwrap();
ett.link(3, 4).unwrap();
ett.link(4, 5).unwrap();
for i in 1..=5 {
for j in 1..=5 {
assert!(ett.connected(i, j));
}
}
assert_eq!(ett.tree_size(1).unwrap(), 5);
}
#[test]
fn test_update_value() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.update_value(1, 10.0).unwrap();
assert_eq!(ett.subtree_aggregate(1).unwrap(), 10.0);
ett.update_value(1, 25.5).unwrap();
assert_eq!(ett.subtree_aggregate(1).unwrap(), 25.5);
}
#[test]
fn test_reroot() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
ett.link(1, 2).unwrap();
ett.link(1, 3).unwrap();
assert!(ett.connected(1, 2));
assert!(ett.connected(2, 3));
assert_eq!(ett.tree_size(1).unwrap(), 3);
ett.reroot(2).unwrap();
assert!(ett.connected(1, 2));
assert!(ett.connected(2, 3));
assert_eq!(ett.tree_size(2).unwrap(), 3);
}
#[test]
fn test_invalid_vertex() {
let ett = EulerTourTree::new();
assert!(matches!(
ett.find_root(999),
Err(MinCutError::InvalidVertex(999))
));
assert!(!ett.connected(1, 2));
}
#[test]
fn test_edge_already_exists() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.link(1, 2).unwrap();
assert!(matches!(ett.link(1, 2), Err(MinCutError::EdgeExists(1, 2))));
}
#[test]
fn test_split_and_merge() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
ett.link(1, 2).unwrap();
ett.link(2, 3).unwrap();
assert!(ett.connected(1, 3));
assert_eq!(ett.tree_size(1).unwrap(), 3);
}
#[test]
fn test_tree_size_updates() {
let mut ett = EulerTourTree::new();
for i in 1..=10 {
ett.make_tree(i).unwrap();
}
for i in 2..=10 {
ett.link(1, i).unwrap();
}
assert_eq!(ett.tree_size(1).unwrap(), 10);
assert_eq!(ett.tree_size(5).unwrap(), 10);
}
#[test]
fn test_empty_tree() {
let ett = EulerTourTree::new();
assert!(ett.is_empty());
assert_eq!(ett.len(), 0);
}
#[test]
fn test_subtree_aggregate_simple() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.update_value(1, 5.0).unwrap();
ett.update_value(2, 3.0).unwrap();
assert_eq!(ett.subtree_aggregate(1).unwrap(), 5.0);
assert_eq!(ett.subtree_aggregate(2).unwrap(), 3.0);
}
#[test]
fn test_reproducible_with_seed() {
let mut ett1 = EulerTourTree::with_seed(12345);
let mut ett2 = EulerTourTree::with_seed(12345);
for i in 1..=5 {
ett1.make_tree(i).unwrap();
ett2.make_tree(i).unwrap();
}
ett1.link(1, 2).unwrap();
ett2.link(1, 2).unwrap();
assert_eq!(ett1.tree_size(1).unwrap(), ett2.tree_size(1).unwrap());
}
#[test]
fn test_large_tree() {
let mut ett = EulerTourTree::new();
let n = 100;
for i in 0..n {
ett.make_tree(i).unwrap();
}
for i in 0..n - 1 {
ett.link(i, i + 1).unwrap();
}
assert_eq!(ett.tree_size(0).unwrap(), n as usize);
assert_eq!(ett.tree_size(n - 1).unwrap(), n as usize);
assert!(ett.connected(0, n - 1));
}
#[test]
fn test_multiple_trees() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
ett.make_tree(4).unwrap();
ett.link(1, 2).unwrap();
ett.link(3, 4).unwrap();
assert!(ett.connected(1, 2));
assert!(ett.connected(3, 4));
assert!(!ett.connected(1, 3));
assert!(!ett.connected(2, 4));
assert_eq!(ett.tree_size(1).unwrap(), 2);
assert_eq!(ett.tree_size(3).unwrap(), 2);
}
#[test]
fn test_bulk_make_trees() {
let mut ett = EulerTourTree::new();
let vertices = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
ett.bulk_make_trees(&vertices).unwrap();
assert_eq!(ett.len(), 10);
for &v in &vertices {
assert!(ett.first_occurrence.contains_key(&v));
}
}
#[test]
fn test_bulk_update_values() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
let updates = vec![(1, 10.0), (2, 20.0), (3, 30.0)];
ett.bulk_update_values(&updates).unwrap();
assert_eq!(ett.nodes[0].value, 10.0);
assert_eq!(ett.nodes[1].value, 20.0);
assert_eq!(ett.nodes[2].value, 30.0);
}
#[test]
fn test_bulk_link() {
let mut ett = EulerTourTree::new();
for i in 1..=5 {
ett.make_tree(i).unwrap();
}
let edges = vec![(1, 2), (2, 3), (3, 4)];
ett.bulk_link(&edges).unwrap();
assert!(ett.connected(1, 4));
assert_eq!(ett.tree_size(1).unwrap(), 4);
}
#[test]
fn test_with_capacity() {
let ett = EulerTourTree::with_seed_and_capacity(42, 100);
assert_eq!(ett.nodes.capacity(), 100);
}
#[test]
fn test_lazy_propagation() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
ett.link(1, 2).unwrap();
ett.link(2, 3).unwrap();
let updates = vec![(1, 100.0), (2, 200.0), (3, 300.0)];
ett.bulk_update_values(&updates).unwrap();
assert_eq!(ett.subtree_aggregate(1).unwrap(), 100.0);
assert_eq!(ett.subtree_aggregate(2).unwrap(), 200.0);
assert_eq!(ett.subtree_aggregate(3).unwrap(), 300.0);
}
#[test]
fn test_cut_edge() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
ett.make_tree(3).unwrap();
ett.link(1, 2).unwrap();
ett.link(2, 3).unwrap();
assert!(ett.connected(1, 3));
assert_eq!(ett.tree_size(1).unwrap(), 3);
ett.cut(2, 3).unwrap();
assert!(ett.connected(1, 2));
assert!(!ett.connected(1, 3));
assert!(!ett.connected(2, 3));
assert_eq!(ett.tree_size(1).unwrap(), 2);
assert_eq!(ett.tree_size(3).unwrap(), 1);
}
#[test]
fn test_cut_and_relink() {
let mut ett = EulerTourTree::new();
for i in 1..=4 {
ett.make_tree(i).unwrap();
}
ett.link(1, 2).unwrap();
ett.link(2, 3).unwrap();
ett.link(3, 4).unwrap();
assert!(ett.connected(1, 4));
assert_eq!(ett.tree_size(1).unwrap(), 4);
ett.cut(2, 3).unwrap();
assert!(ett.connected(1, 2));
assert!(ett.connected(3, 4));
assert!(!ett.connected(1, 3));
assert!(!ett.connected(2, 4));
ett.link(1, 4).unwrap();
assert!(ett.connected(1, 3));
assert_eq!(ett.tree_size(1).unwrap(), 4);
}
#[test]
fn test_cut_nonexistent_edge() {
let mut ett = EulerTourTree::new();
ett.make_tree(1).unwrap();
ett.make_tree(2).unwrap();
assert!(matches!(
ett.cut(1, 2),
Err(MinCutError::EdgeNotFound(1, 2))
));
}
}