use std::num::Int;
use super::graph::IndexType;
#[derive(Debug, Clone)]
pub struct UnionFind<K>
{
parent: Vec<K>,
rank: Vec<u8>,
}
#[inline]
fn to_uint<K: IndexType>(x: K) -> usize { x.index() }
#[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 + Int
{
pub fn new(n: usize) -> Self
{
let mut parent = Vec::with_capacity(n);
let mut rank = Vec::with_capacity(n);
for _ in 0..n {
rank.push(0)
}
let mut i: K = Int::zero();
if n > 0 {
parent.push(i);
}
for _ in 1..n {
i = i + Int::one();
parent.push(i);
}
UnionFind{parent: parent, rank: rank}
}
pub fn find(&self, x: K) -> K
{
assert!(to_uint(x) < self.parent.len());
unsafe {
let mut x = x;
loop {
let xparent = *get_unchecked(&self.parent, to_uint(x));
if xparent == x {
break
}
x = xparent;
}
x
}
}
pub fn find_mut(&mut self, x: K) -> K
{
assert!(to_uint(x) < 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, to_uint(x));
if xparent != x {
let xrep = self.find_mut_recursive(xparent);
let xparent = self.parent.get_unchecked_mut(to_uint(x));
*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 = to_uint(xrep);
let yrepu = to_uint(yrep);
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
}
}