use std::hash::Hash;
use crate::{
index::{intern::InternMap, vec::IndexVec},
index_type,
};
index_type!(DSUNode);
#[derive(Default, Clone)]
struct DSUBase {
nodes: IndexVec<DSUNode, DSUNode>,
weights: IndexVec<DSUNode, u32>,
}
impl DSUBase {
fn new() -> DSUBase {
DSUBase {
nodes: IndexVec::new(),
weights: IndexVec::new(),
}
}
fn track_new_node(&mut self, node: DSUNode) {
let node2 = self.nodes.push(node);
debug_assert!(node == node2);
self.weights.push(1);
}
fn find(&mut self, node: DSUNode) -> DSUNode {
let mut cur = node;
loop {
let next = self.nodes[cur];
if cur == next {
self.nodes[node] = cur;
return cur;
}
cur = next;
}
}
fn union(&mut self, n1: DSUNode, n2: DSUNode) {
let n1 = self.find(n1);
let n2 = self.find(n2);
if n1 == n2 {
return;
}
let parent;
let child;
if self.weights[n1] < self.weights[n2] {
child = n1;
parent = n2;
} else {
child = n2;
parent = n1;
}
self.nodes[child] = parent;
self.weights[parent] += self.weights[child];
}
}
pub struct DSU<Node: Copy + Eq + Hash> {
nodes: InternMap<DSUNode, Node>,
dsu: DSUBase,
}
impl<Node: Copy + Eq + Hash> DSU<Node> {
pub fn new() -> DSU<Node> {
DSU {
nodes: InternMap::new(),
dsu: DSUBase::new(),
}
}
fn node_to_id(&mut self, node: Node) -> DSUNode {
let w = self.nodes.watermark();
let id = self.nodes.push(&node);
if w != self.nodes.watermark() {
self.dsu.track_new_node(id);
}
id
}
pub fn find(&mut self, node: Node) -> Node {
if let Some(node) = self.nodes.try_push(&node) {
let node = self.dsu.find(node);
self.nodes[node]
} else {
node
}
}
pub fn union(&mut self, a: Node, b: Node) {
let a = self.node_to_id(a);
let b = self.node_to_id(b);
self.dsu.union(a, b);
}
}