use std::fmt::Debug;
use crate::utils::consts::INF;
pub trait TreeMonoid {
type T: Clone + Debug;
type W: Clone;
fn id() -> Self::T;
fn merge(x: &Self::T, y: &Self::T) -> Self::T;
fn put_edge(x: &Self::T, weight: &Self::W) -> Self::T;
}
pub mod examples {
use super::TreeMonoid;
pub struct Diameter;
impl TreeMonoid for Diameter {
type T = isize;
type W = isize;
fn id() -> Self::T {
0
}
fn merge(x: &Self::T, y: &Self::T) -> Self::T {
*x.max(y)
}
fn put_edge(x: &Self::T, weight: &Self::W) -> Self::T {
x + weight
}
}
}
pub type Graph<T> = Vec<Vec<Edge<T>>>;
#[derive(Clone, Debug)]
pub struct Edge<T> {
pub to: usize,
pub weight: T,
}
pub struct Rerooting<M: TreeMonoid> {
pub dp: Vec<Vec<M::T>>,
pub ans: Vec<M::T>,
pub G: Graph<M::W>,
}
impl<M: TreeMonoid> Rerooting<M> {
pub fn new(N: usize) -> Self {
Self {
dp: vec![vec![]; N],
ans: vec![M::id(); N],
G: vec![vec![]; N],
}
}
pub fn add_edge(&mut self, u: usize, v: usize, w: M::W) {
self.G[u].push(Edge { to: v, weight: w });
}
pub fn add_edge2(&mut self, u: usize, v: usize, w: M::W) {
self.G[u].push(Edge {
to: v,
weight: w.clone(),
});
self.G[v].push(Edge { to: u, weight: w });
}
pub fn build(&mut self) {
self.aggregate(INF, 0);
self.reroot(INF, 0, &M::id());
}
pub fn aggregate(&mut self, p: usize, u: usize) -> M::T {
let mut res = M::id();
let deg = self.G[u].len();
self.dp[u] = vec![M::id(); deg];
for i in 0..deg {
let Edge { to: v, weight } = self.G[u][i].clone();
if v == p {
continue;
}
let mut val = self.aggregate(u, v);
val = M::put_edge(&val, &weight);
res = M::merge(&res, &val);
self.dp[u][i] = val;
}
res
}
pub fn reroot(&mut self, p: usize, u: usize, dp_p: &M::T) {
let deg = self.G[u].len();
for i in 0..deg {
let Edge { to: v, weight } = &self.G[u][i];
if *v == p {
self.dp[u][i] = M::put_edge(dp_p, weight);
}
}
let mut Sl = vec![M::id(); deg + 1];
let mut Sr = vec![M::id(); deg + 1];
for i in 0..deg {
Sl[i + 1] = M::merge(&Sl[i], &self.dp[u][i]);
}
for i in (0..deg).rev() {
Sr[i] = M::merge(&self.dp[u][i], &Sr[i + 1]);
}
self.ans[u] = Sl[deg].clone();
for i in 0..deg {
let v = self.G[u][i].to;
if v == p {
continue;
}
let val = M::merge(&Sl[i], &Sr[i + 1]);
self.reroot(u, v, &val);
}
}
}