macro_rules !read_value {($iter :expr ,($($t :tt ) ,*) ) =>{($(read_value !($iter ,$t ) ) ,*) } ;($iter :expr ,[$t :tt ;$len :expr ] ) =>{(0 ..$len ) .map (|_ |read_value !($iter ,$t ) ) .collect ::<Vec <_ >>() } ;($iter :expr ,{chars :$base :expr } ) =>{read_value !($iter ,String ) .chars () .map (|c |(c as u8 -$base as u8 ) as usize ) .collect ::<Vec <usize >>() } ;($iter :expr ,{char :$base :expr } ) =>{read_value !($iter ,{chars :$base } ) [0 ] } ;($iter :expr ,chars ) =>{read_value !($iter ,String ) .chars () .collect ::<Vec <char >>() } ;($iter :expr ,char ) =>{read_value !($iter ,chars ) [0 ] } ;($iter :expr ,usize1 ) =>{read_value !($iter ,usize ) -1 } ;($iter :expr ,$t :ty ) =>{$iter .next () .unwrap () .parse ::<$t >() .unwrap () } ;}
macro_rules !input_inner {($iter :expr ) =>{} ;($iter :expr ,) =>{} ;($iter :expr ,mut $var :ident :$t :tt $($r :tt ) *) =>{let mut $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,mut $var :ident $($r :tt ) *) =>{input_inner !{$iter ,mut $var :usize $($r ) *} } ;($iter :expr ,$var :ident :$t :tt $($r :tt ) *) =>{let $var =read_value !($iter ,$t ) ;input_inner !{$iter $($r ) *} } ;($iter :expr ,$var :ident $($r :tt ) *) =>{input_inner !{$iter ,$var :usize $($r ) *} } ;}
macro_rules !input {(source =$s :expr ,$($r :tt ) *) =>{let mut iter =$s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;(iter =$iter :ident ,$($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut $iter =s .split_whitespace () ;input_inner !{$iter ,$($r ) *} } ;($($r :tt ) *) =>{let s ={use std ::io ::Read ;let mut s =String ::new () ;std ::io ::stdin () .read_to_string (&mut s ) .unwrap () ;s } ;let mut iter =s .split_whitespace () ;input_inner !{iter ,$($r ) *} } ;}
pub trait Magma {
    type T: Clone + PartialEq;
    fn operate(&self, x: &Self::T, y: &Self::T) -> Self::T;
}
pub trait Associative {}
pub trait SemiGroup: Magma + Associative {}
pub trait Unital: Magma {
    fn unit(&self) -> Self::T;
}
pub trait Monoid: SemiGroup + Unital {
    fn power(&self, x: Self::T, n: usize) -> Self::T {
        let mut n = n;
        let mut res = self.unit();
        let mut base = x;
        while n > 0 {
            if n & 1 == 1 {
                res = self.operate(&res, &base);
            }
            base = self.operate(&base, &base);
            n = n >> 1;
        }
        res
    }
}
pub trait Invertible: Magma {
    fn inverse(&self, x: &Self::T) -> Self::T;
}
pub trait Group: Monoid + Invertible {}
pub trait Commutative {}
pub trait AbelianMonoid: Monoid + Commutative {}
pub trait AbelianGroup: Group + Commutative {}
pub trait Idempotent {}
pub trait IdempotentMonoid: Monoid + Idempotent {}
#[derive(Clone, Debug, Default)]
pub struct EulerTourForVertex {
    vidx: Vec<(usize, usize)>,
    vpos: usize,
}
impl EulerTourForVertex {
    pub fn new(vsize: usize) -> Self {
        EulerTourForVertex {
            vidx: vec![(0, 0); vsize],
            vpos: 0,
        }
    }
    pub fn len(&self) -> usize {
        self.vpos
    }
    pub fn subtree_vertex_tour(&mut self, u: usize, p: usize, graph: &Graph) {
        self.vidx[u].0 = self.vpos;
        self.vpos += 1;
        for a in graph.adjacency(u) {
            if a.to != p {
                self.subtree_vertex_tour(a.to, u, graph);
            }
        }
        self.vidx[u].1 = self.vpos;
    }
    pub fn path_vertex_tour(&mut self, u: usize, p: usize, graph: &Graph) {
        self.vidx[u].0 = self.vpos;
        self.vpos += 1;
        for a in graph.adjacency(u) {
            if a.to != p {
                self.path_vertex_tour(a.to, u, graph);
            }
        }
        self.vidx[u].1 = self.vpos;
        self.vpos += 1;
    }
    pub fn subtree_query<T, F: FnMut(usize, usize) -> T>(&self, u: usize, mut f: F) -> T {
        let (l, r) = self.vidx[u];
        f(l, r)
    }
    pub fn subtree_update<T, F: FnMut(usize, T)>(&self, u: usize, x: T, mut f: F) {
        let (l, _r) = self.vidx[u];
        f(l, x);
    }
    pub fn path_query<T, F: FnMut(usize, usize) -> T>(&self, u: usize, v: usize, mut f: F) -> T {
        let (mut l, mut r) = (self.vidx[u].0, self.vidx[v].0);
        if l > r {
            std::mem::swap(&mut l, &mut r);
        }
        f(l, r + 1)
    }
    pub fn path_update<T, F: FnMut(usize, T)>(&self, u: usize, x: T, invx: T, mut f: F) {
        let (l, r) = self.vidx[u];
        f(l, x);
        f(r, invx);
    }
}
#[derive(Clone, Debug)]
pub struct SegmentTree<M: Monoid> {
    pub n: usize,
    pub seg: Vec<M::T>,
    pub m: M,
}
impl<M: Monoid> SegmentTree<M> {
    pub fn new(n: usize, m: M) -> SegmentTree<M> {
        let n = 1 << format!("{:b}", n - 1).len();
        let seg = vec![m.unit(); 2 * n];
        SegmentTree {
            n: n,
            seg: seg,
            m: m,
        }
    }
    pub fn from_vec(v: Vec<M::T>, m: M) -> SegmentTree<M> {
        let n = 1 << format!("{:b}", v.len() - 1).len();
        let mut seg = vec![m.unit(); 2 * n];
        for (i, x) in v.into_iter().enumerate() {
            seg[n + i] = x;
        }
        for i in (1..n).rev() {
            seg[i] = m.operate(&seg[2 * i], &seg[2 * i + 1]);
        }
        SegmentTree {
            n: n,
            seg: seg,
            m: m,
        }
    }
    pub fn set(&mut self, k: usize, x: M::T) {
        debug_assert!(k < self.n);
        let mut k = k + self.n;
        self.seg[k] = x;
        k /= 2;
        while k > 0 {
            self.seg[k] = self.m.operate(&self.seg[2 * k], &self.seg[2 * k + 1]);
            k /= 2;
        }
    }
    pub fn update(&mut self, k: usize, x: M::T) {
        debug_assert!(k < self.n);
        let mut k = k + self.n;
        self.seg[k] = self.m.operate(&self.seg[k], &x);
        k /= 2;
        while k > 0 {
            self.seg[k] = self.m.operate(&self.seg[2 * k], &self.seg[2 * k + 1]);
            k /= 2;
        }
    }
    pub fn get(&self, k: usize) -> M::T {
        debug_assert!(k < self.n);
        self.seg[k + self.n].clone()
    }
    pub fn fold(&self, l: usize, r: usize) -> M::T {
        debug_assert!(l < self.n);
        debug_assert!(r <= self.n);
        let mut l = l + self.n;
        let mut r = r + self.n;
        let mut vl = self.m.unit();
        let mut vr = self.m.unit();
        while l < r {
            if l & 1 != 0 {
                vl = self.m.operate(&vl, &self.seg[l]);
                l += 1;
            }
            if r & 1 != 0 {
                r -= 1;
                vr = self.m.operate(&self.seg[r], &vr);
            }
            l /= 2;
            r /= 2;
        }
        self.m.operate(&vl, &vr)
    }
    pub fn fold_all(&self) -> M::T {
        self.seg[1].clone()
    }
    /// left most index [0, r) that satisfies monotonic condition
    pub fn lower_bound_all<F: Fn(&M::T) -> bool>(&self, f: F, r: usize) -> usize {
        if !f(&self.seg[1]) {
            return r;
        }
        let mut acc = self.m.unit();
        let mut pos = 1;
        while pos < self.n {
            pos *= 2;
            let y = self.m.operate(&acc, &self.seg[pos]);
            if !f(&y) {
                acc = y;
                pos += 1;
            }
        }
        std::cmp::min(pos - self.n, r)
    }
    /// left most index [l, r) that satisfies monotonic condition
    pub fn lower_bound<F: Fn(&M::T) -> bool>(&self, f: F, l: usize, r: usize) -> usize {
        let mut acc = self.m.unit();
        let mut pos = l + self.n;
        let mut lim = r + self.n;
        loop {
            let y = self.m.operate(&acc, &self.seg[pos]);
            if f(&y) {
                while pos < self.n {
                    pos *= 2;
                    let y = self.m.operate(&acc, &self.seg[pos]);
                    if !f(&y) {
                        acc = y;
                        pos += 1;
                    }
                }
                return std::cmp::min(pos - self.n, r);
            }
            let is_right = pos & 1 == 1;
            if pos == lim {
                return r;
            }
            pos /= 2;
            lim /= 2;
            if is_right {
                acc = y;
                pos += 1;
            }
        }
    }
}
#[derive(Clone, Debug)]
pub struct AdditiveOperation<T: Copy + PartialEq + std::ops::Add<Output = T>> {
    zero: T,
}
pub mod additive_operation_impl {
    use super::*;
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> AdditiveOperation<T> {
        pub fn new(zero: T) -> Self {
            AdditiveOperation { zero: zero }
        }
    }
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> Magma for AdditiveOperation<T> {
        type T = T;
        #[inline]
        fn operate(&self, x: &Self::T, y: &Self::T) -> Self::T {
            *x + *y
        }
    }
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> Unital for AdditiveOperation<T> {
        #[inline]
        fn unit(&self) -> Self::T {
            self.zero.clone()
        }
    }
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> Associative for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> SemiGroup for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> Monoid for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> Commutative for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + std::ops::Add<Output = T>> AbelianMonoid for AdditiveOperation<T> {}
    impl<T: Copy + PartialEq + std::ops::Add<Output = T> + std::ops::Neg<Output = T>> Invertible
        for AdditiveOperation<T>
    {
        #[inline]
        fn inverse(&self, x: &Self::T) -> Self::T {
            -*x
        }
    }
    impl<T: Copy + PartialEq + std::ops::Add<Output = T> + std::ops::Neg<Output = T>> Group
        for AdditiveOperation<T>
    {
    }
    impl<T: Copy + PartialEq + std::ops::Add<Output = T> + std::ops::Neg<Output = T>> AbelianGroup
        for AdditiveOperation<T>
    {
    }
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Adjacent {
    pub to: usize,
    pub id: usize,
}
impl Adjacent {
    pub fn new(to: usize, id: usize) -> Adjacent {
        Adjacent { to: to, id: id }
    }
}
#[derive(Clone, Debug, Default)]
pub struct Graph {
    pub vsize: usize,
    pub esize: usize,
    pub graph: Vec<Vec<Adjacent>>,
}
impl Graph {
    pub fn new(vsize: usize) -> Graph {
        Graph {
            vsize: vsize,
            esize: 0,
            graph: vec![vec![]; vsize],
        }
    }
    pub fn add_edge(&mut self, from: usize, to: usize) {
        self.graph[from].push(Adjacent::new(to, self.esize));
        self.esize += 1;
    }
    pub fn add_undirected_edge(&mut self, u: usize, v: usize) {
        self.graph[u].push(Adjacent::new(v, self.esize));
        self.graph[v].push(Adjacent::new(u, self.esize));
        self.esize += 1;
    }
    pub fn vertices(&self) -> std::ops::Range<usize> {
        0..self.vsize
    }
    pub fn adjacency(&self, from: usize) -> &Vec<Adjacent> {
        &self.graph[from]
    }
}
impl Graph {
    fn size_dfs(&self, u: usize, p: usize, size: &mut Vec<u64>) {
        size[u] = 1;
        for a in self.adjacency(u) {
            if a.to != p {
                self.size_dfs(a.to, u, size);
                size[u] += size[a.to];
            }
        }
    }
    pub fn tree_size(&self, root: usize) -> Vec<u64> {
        let n = self.vsize;
        let mut size = vec![0; n];
        self.size_dfs(root, n, &mut size);
        size
    }
}
fn main() {
    input! { n, c: [usize1; n], ab: [(usize1,usize1); n-1] };
    let mut g = Graph::new(n);
    for &(a, b) in &ab {
        g.add_undirected_edge(a, b);
    }
    let mut euler = EulerTourForVertex::new(n);
    euler.subtree_vertex_tour(0, n, &g);
    let mut seg = SegmentTree::new(n, AdditiveOperation::new(0i64));
    for u in 0..n {
        euler.subtree_update(u, 1, |k, x| seg.update(k, x));
    }
    let mut cs = vec![vec![]; n];
    for i in 0..n {
        cs[c[i]].push(i);
    }
    for k in 0..n {
        cs[k].sort_by_key(|&u| std::cmp::Reverse(euler.vidx[u].0));
        let mut ans = (n * (n + 1) / 2) as i64;
        let mut hist = vec![];
        for &u in cs[k].iter() {
            let mut t = 1i64;
            for a in g.adjacency(u) {
                if euler.vidx[u].0 > euler.vidx[a.to].0 {
                    continue;
                }
                let d = euler.subtree_query(a.to, |l, r| seg.fold(l, r));
                ans -= d * (d + 1) / 2;
                t += d;
            }
            euler.subtree_update(u, -t, |k, x| seg.update(k, x));
            hist.push((u, t));
        }
        let d = seg.fold_all();
        ans -= d * (d + 1) / 2;
        for (u, t) in hist.into_iter() {
            euler.subtree_update(u, t, |k, x| seg.update(k, x));
        }
        println!("{}", ans);
    }
}


Measured memory_bytes: 55396