Push-Relabel Flow

type Capacity = i32;
struct Flow {
    head: Vec<u32>,
    link: Vec<(u32, u32)>,
    f: Vec<Capacity>,
    x: Vec<Capacity>,
    next: Vec<i32>,
    last: Vec<i32>,
    gn: Vec<i32>,
    gp: Vec<i32>,
    ff: Vec<u32>,
    h: Vec<i32>,
    high: i32,
    high_gap: i32,
    work: usize,
}

impl Flow {
    fn new(v: usize, e: usize) -> Self {
        Self {
            head: vec![u32::MAX; v],
            link: Vec::with_capacity(e),
            f: Vec::with_capacity(e),
            x: Vec::with_capacity(e),
            gn: vec![],
            gp: vec![],
            h: vec![],
            high: 0,
            high_gap: 0,
            work: 0,
            next: vec![],
            last: vec![],
            ff: vec![],
        }
    }
    fn connect(&mut self, from: usize, to: usize, cap: Capacity, directed: bool) {
        let p = self.head[from];
        self.head[from] = self.link.len() as u32;
        self.link.push((p, to as u32));
        self.f.push(cap);
        let p = self.head[to];
        self.head[to] = self.link.len() as u32;
        self.link.push((p, from as u32));
        self.f.push(if directed { 0 } else { cap });
    }
    fn push_last(&mut self, h: i32, u: usize) {
        self.next[u] = self.last[h as usize];
        self.last[h as usize] = u as i32;
    }
    fn update_h(&mut self, u: usize, mut new_h: i32) {
        if self.h[u] as usize != self.head.len() {
            self.gn[self.gp[u] as usize] = self.gn[u];
            self.gp[self.gn[u] as usize] = self.gp[u];
        }
        self.h[u] = new_h as i32;
        if new_h == self.head.len() as i32 {
            return;
        }
        self.high_gap = self.high_gap.max(new_h);
        if self.x[u] > 0 {
            self.high = self.high.max(new_h);
            self.push_last(new_h, u);
        }
        new_h += self.head.len() as i32;
        self.gn[u] = self.gn[new_h as usize];
        self.gp[u] = new_h as i32;
        self.gn[new_h as usize] = u as i32;
        self.gp[self.gn[u] as usize] = u as i32;
    }
    fn global_relabel(&mut self, t: usize) {
        self.work = 0;
        self.h.clear();
        self.h
            .extend(std::iter::repeat(self.head.len() as i32).take(self.head.len()));
        self.last.clear();
        self.last.resize(self.head.len() + 1, -1);
        self.gn[..self.head.len()]
            .iter_mut()
            .enumerate()
            .for_each(|(i, v)| *v = i as i32);
        self.gp[..self.head.len()]
            .iter_mut()
            .enumerate()
            .for_each(|(i, v)| *v = i as i32);
        self.h[t] = 0;
        let mut q = vec![t as u32];
        let mut i = 0;
        while let Some(&u) = q.get(i) {
            let mut e = self.head[u as usize];
            while let Some(&(next, v)) = self.link.get(e as usize) {
                if self.h[v as usize] == self.head.len() as i32 && self.f[(e ^ 1) as usize] > 0 {
                    q.push(v);
                    self.update_h(v as usize, self.h[u as usize] + 1);
                }
                e = next;
            }
            self.high_gap = self.h[u as usize];
            self.high = self.high_gap;
            i += 1;
        }
    }
    fn push(&mut self, u: usize, v: usize, e: usize) {
        let df = self.x[u].min(self.f[e]);
        if df <= 0 {
            return;
        }
        if self.x[v] == 0 {
            self.push_last(self.h[v], v as usize);
        }
        self.f[e] -= df;
        self.f[e ^ 1] += df;
        self.x[u] -= df;
        self.x[v] += df;
    }
    fn discharge(&mut self, u: usize) {
        let mut new_h = self.head.len() as i32;
        let mut e = self.ff[u];
        while let Some(&(next, v)) = self.link.get(e as usize) {
            if self.f[e as usize] > 0 {
                if self.h[u] == self.h[v as usize] + 1 {
                    self.push(u, v as usize, e as usize);
                    if self.x[u] <= 0 {
                        self.ff[u] = e;
                        return;
                    }
                } else {
                    new_h = new_h.min(self.h[v as usize] + 1);
                }
            }
            e = next;
        }
        let mut e = self.head[u];
        while e != self.ff[u] {
            let (next, v) = self.link[e as usize];
            if self.f[e as usize] > 0 {
                if self.h[u] == self.h[v as usize] + 1 {
                    self.push(u, v as usize, e as usize);
                    if self.x[u] <= 0 {
                        self.ff[u] = e;
                        return;
                    }
                } else {
                    new_h = new_h.min(self.h[v as usize] + 1);
                }
            }
            e = next;
        }
        self.work += 1;
        let h = self.h[u] + self.head.len() as i32;
        if self.gn[self.gn[h as usize] as usize] != h {
            self.update_h(u, new_h);
        } else {
            let old = self.h[u];
            for h in old..=self.high_gap {
                let mut u = self.gn[(h + self.head.len() as i32) as usize] as usize;
                while u < self.head.len() {
                    self.h[u] = self.head.len() as i32;
                    u = self.gn[u] as usize;
                }
                let uh = h + self.head.len() as i32;
                self.gp[uh as usize] = uh;
                self.gn[uh as usize] = uh;
            }
            self.high_gap = old - 1;
        }
    }
    fn run(&mut self, s: usize, t: usize) -> Capacity {
        self.ff.clear();
        self.ff.extend_from_slice(&self.head);
        self.x.clear();
        self.x.resize(self.head.len(), 0);
        self.x[s] = Capacity::MAX;
        self.x[t] = -Capacity::MAX;
        self.gn.clear();
        self.gn.resize(self.head.len() * 2, 0);
        self.gp.clear();
        self.gp.resize(self.head.len() * 2, 0);
        self.next.clear();
        self.next.resize(self.head.len(), 0);
        self.global_relabel(t);
        let mut e = self.head[s];
        while let Some(&(next, v)) = self.link.get(e as usize) {
            self.push(s, v as usize, e as usize);
            e = next;
        }
        while self.high >= 0 {
            while self.last[self.high as usize] != -1 {
                let u = self.last[self.high as usize];
                self.last[self.high as usize] = self.next[u as usize];
                if self.h[u as usize] == self.high {
                    self.discharge(u as usize);
                    if self.work > 4 * self.head.len() {
                        self.global_relabel(t);
                    }
                }
            }
            self.high -= 1;
        }
        self.x[t] + i32::MAX
    }
}