use super::graph::IndexType;
#[derive(Debug, Clone)]
pub struct UnionFind<K>
{
parent: Vec<K>,
rank: Vec<u8>,
}
#[inline]
unsafe fn get_unchecked<K>(xs: &[K], index: usize) -> &K
{
debug_assert!(index < xs.len());
xs.get_unchecked(index)
}
impl<K> UnionFind<K>
where K: IndexType
{
pub fn new(n: usize) -> Self
{
let rank = vec![0; n];
let parent = (0..n).map(K::new).collect::<Vec<K>>();
UnionFind{parent: parent, rank: rank}
}
pub fn find(&self, x: K) -> K
{
assert!(x.index() < self.parent.len());
unsafe {
let mut x = x;
loop {
let xparent = *get_unchecked(&self.parent, x.index());
if xparent == x {
break
}
x = xparent;
}
x
}
}
pub fn find_mut(&mut self, x: K) -> K
{
assert!(x.index() < self.parent.len());
unsafe {
self.find_mut_recursive(x)
}
}
unsafe fn find_mut_recursive(&mut self, x: K) -> K
{
let xparent = *get_unchecked(&self.parent, x.index());
if xparent != x {
let xrep = self.find_mut_recursive(xparent);
let xparent = self.parent.get_unchecked_mut(x.index());
*xparent = xrep;
*xparent
} else {
xparent
}
}
pub fn union(&mut self, x: K, y: K) -> bool
{
if x == y {
return false
}
let xrep = self.find_mut(x);
let yrep = self.find_mut(y);
if xrep == yrep {
return false
}
let xrepu = xrep.index();
let yrepu = yrep.index();
let xrank = self.rank[xrepu];
let yrank = self.rank[yrepu];
if xrank < yrank {
self.parent[xrepu] = yrep;
} else if xrank > yrank {
self.parent[yrepu] = xrep;
} else {
self.parent[yrepu] = xrep;
self.rank[xrepu] += 1;
}
true
}
pub fn into_labeling(mut self) -> Vec<K>
{
unsafe {
for ix in 0..self.parent.len() {
let k = *get_unchecked(&self.parent, ix);
let xrep = self.find_mut_recursive(k);
*self.parent.get_unchecked_mut(ix) = xrep;
}
}
self.parent
}
}