Problem:
Score : 800 points

Problem Statement

There is a tree with N vertices numbered 1 through N.
The i-th edge connects Vertex x_i and y_i.
Each vertex is painted white or black.
The initial color of Vertex i is represented by a letter c_i.
c_i = W represents the vertex is white; c_i = B represents the vertex is black.

A cat will walk along this tree.
More specifically, she performs one of the following in one second repeatedly:

Choose a vertex that is adjacent to the vertex where she is currently, and move to that vertex. Then, invert the color of the destination vertex.

Invert the color of the vertex where she is currently.

The cat's objective is to paint all the vertices black. She may start and end performing actions at any vertex.
At least how many seconds does it takes for the cat to achieve her objective?

Constraints

1 ≤ N ≤ 10^5

1 ≤ x_i,y_i ≤ N (1 ≤ i ≤ N-1)

The given graph is a tree.

c_i = W or c_i = B.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_{N-1} y_{N-1}
c_1c_2..c_N

Output

Print the minimum number of seconds required to achieve the objective.

Sample Input 1

5
1 2
2 3
2 4
4 5
WBBWW

Sample Output 1

5

The objective can be achieved in five seconds, for example, as follows:

Start at Vertex 1. Change the color of Vertex 1 to black.

Move to Vertex 2, then change the color of Vertex 2 to white.

Change the color of Vertex 2 to black.

Move to Vertex 4, then change the color of Vertex 4 to black.

Move to Vertex 5, then change the color of Vertex 5 to black.

Sample Input 2

6
3 1
4 5
2 6
6 1
3 4
WWBWBB

Sample Output 2

7

Sample Input 3

1
B

Sample Output 3

0

Sample Input 4

20
2 19
5 13
6 4
15 6
12 19
13 19
3 11
8 3
3 20
16 13
7 14
3 17
7 8
10 20
11 9
8 18
8 2
10 1
6 13
WBWBWBBWWWBBWWBBBBBW

Sample Output 4

21

Solution in Rust (1.15.1) (judge verdict: Accepted)

use std::io::*;
use std::str::FromStr;
use std::collections::HashMap;

#[allow(dead_code)]
fn read<T: FromStr>() -> T {
    let stdin = stdin();
    let stdin = stdin.lock();
    let token: String = stdin
        .bytes()
        .map(|c| c.expect("failed to read char") as char)
        .skip_while(|c| c.is_whitespace())
        .take_while(|c| !c.is_whitespace())
        .collect();
    token.parse().ok().expect("failed to parse token")
}

type Weight = i32;
#[allow(dead_code)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct Edge {
    index: usize,
    src: usize,
    dest: usize,
    weight: Weight,
}
#[allow(dead_code)]
impl Edge {
    fn new(index: usize, src: usize, dest: usize, weight: Weight) -> Edge {
        Edge {
            index: index,
            src: src,
            dest: dest,
            weight: weight,
        }
    }
}
impl std::cmp::Ord for Edge {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (self.weight, self.src, self.dest).cmp(&(other.weight, other.src, other.dest))
    }
}
impl std::cmp::PartialOrd for Edge {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        Some(self.cmp(other))
    }
}
type Edges = Vec<Edge>;
type Graph = Vec<Edges>;
#[allow(dead_code)]
fn graph_new(n: usize) -> Graph {
    vec![vec![]; n]
}
#[allow(dead_code)]
fn add_bi_edge(graph: &mut Graph, index: &mut usize, src: usize, dest: usize, weight: Weight) {
    graph[src].push(Edge::new(*index, src, dest, weight));
    *index += 1;
    graph[dest].push(Edge::new(*index, dest, src, weight));
    *index += 1;
}

struct Solver {
    n: usize,
    g: Graph,
    edge_index: HashMap<(usize, usize), usize>,
    initial_colors: Vec<usize>,
    memo: Vec<Vec<i64>>,
    memo_all_black: Vec<Option<bool>>,
    memo_total: Vec<(usize, i64)>,
    memo_childs: Vec<Vec<(i64, i64, i64, usize)>>,
    memo_all_black_total: Vec<i64>,
    visit_cnt: Vec<Vec<i64>>,
    visit_cnt_all_black: Vec<i64>,
}

impl Solver {
    fn new() -> Solver {
        let n = read::<usize>();
        let mut g = graph_new(n);
        let mut edge_index = HashMap::<(usize, usize), usize>::new();
        let mut e = 0;
        for _ in 0..n - 1 {
            let x = read::<usize>() - 1;
            let y = read::<usize>() - 1;
            edge_index.insert((x, y), e);
            edge_index.insert((y, x), e + 1);
            add_bi_edge(&mut g, &mut e, x, y, 0);
        }
        let initial_colors = read::<String>()
            .chars()
            .map(|c| if c == 'W' { 0 } else { 1 })
            .collect::<Vec<usize>>();
        Solver {
            n: n,
            g: g,
            edge_index: edge_index,
            initial_colors: initial_colors,
            memo: vec![vec![-1; 2 * (n - 1)]; 2],
            memo_all_black: vec![None; 2 * (n - 1)],
            memo_total: vec![(0, -1); n],
            memo_childs: vec![vec![]; n],
            memo_all_black_total: vec![-1; n],
            visit_cnt: vec![vec![0; n]; 2],
            visit_cnt_all_black: vec![0; n],
        }
    }
    fn move_edge_all_black(&mut self, edge: &Edge) -> bool {
        if self.memo_all_black[edge.index].is_some() {
            return self.memo_all_black[edge.index].unwrap();
        }
        let ret = self.all_black(edge.dest, edge.src);
        self.memo_all_black[edge.index] = Some(ret);
        ret
    }
    fn all_black(&mut self, from: usize, parent: usize) -> bool {
        if self.initial_colors[from] == 0 {
            return false;
        }
        self.visit_cnt_all_black[from] += 1;
        if self.visit_cnt_all_black[from] > 2 {
            if self.memo_all_black_total[from] == -1 {
                let mut sum = 0;
                for edge in self.g[from].clone().iter() {
                    sum += if self.move_edge_all_black(edge) { 1 } else { 0 };
                }
                self.memo_all_black_total[from] = sum;
            }
            let rev_index = self.edge_index[&(from, parent)];
            let mut cnt = self.memo_all_black_total[from];
            cnt -= if self.memo_all_black[rev_index].unwrap() {
                1
            } else {
                0
            };
            return cnt == self.g[from].len() as i64 - 1;
        }
        for edge in self.g[from].clone().iter() {
            if edge.dest == parent {
                continue;
            }
            if !self.move_edge_all_black(edge) {
                return false;
            }
        }
        true
    }
    fn move_edge(&mut self, back: usize, edge: &Edge) -> i64 {
        if self.memo[back][edge.index] != -1 {
            return self.memo[back][edge.index];
        }
        let c = self.initial_colors[edge.dest] ^ 1;
        let ret = back as i64 + 1 + self.dfs(back, c, edge.dest, edge.src);
        self.memo[back][edge.index] = ret;
        ret
    }
    fn dfs(&mut self, back: usize, c: usize, from: usize, parent: usize) -> i64 {
        self.visit_cnt[back][from] += 1;
        if c != self.initial_colors[from] && self.visit_cnt[back][from] > 2 {
            let mut c = c;
            let mut childs = vec![];
            if self.memo_total[from].1 == -1 {
                let mut sum = 0;
                for edge in self.g[from].clone().iter() {
                    if self.move_edge_all_black(edge) {
                        continue;
                    }
                    c ^= 1;
                    let one_way = self.move_edge(0, edge);
                    let need_back = self.move_edge(1, edge);
                    let diff = need_back - one_way;
                    childs.push((diff, need_back, one_way, edge.dest));
                    sum += need_back;
                }
                childs.sort();
                childs.reverse();
                self.memo_total[from] = (c, sum);
                self.memo_childs[from] = childs;
            }
            let rev_index = self.edge_index[&(from, parent)];
            let mut c = self.memo_total[from].0;
            let mut ret = self.memo_total[from].1;
            if !self.memo_all_black[rev_index].unwrap() {
                c ^= 1;
                ret -= self.memo[1][rev_index];
            }
            if back == 0 && self.memo_childs[from].len() > 0 {
                if self.memo_childs[from][0].3 != parent {
                    c ^= 1;
                    ret -= self.memo_childs[from][0].0;
                } else if self.memo_childs[from].len() > 1 {
                    c ^= 1;
                    ret -= self.memo_childs[from][1].0;
                }
            }
            if c == 0 {
                ret += 1;
            }
            return ret;
        }
        let mut c = c;
        let mut ret = 0;
        let mut childs = vec![];
        for edge in self.g[from].clone().iter() {
            if edge.dest == parent || self.move_edge_all_black(edge) {
                continue;
            }
            c ^= 1;
            let one_way = self.move_edge(0, edge);
            let need_back = self.move_edge(1, edge);
            let diff = need_back - one_way;
            childs.push((diff, need_back, one_way));
            ret += need_back;
        }
        childs.sort();
        childs.reverse();
        if back == 0 && childs.len() > 0 {
            // println!("{} {:?}", from, childs);
            c ^= 1;
            ret -= childs[0].0;
        }
        if c == 0 {
            ret += 1;
        }
        ret
    }
    fn solve(&mut self) {
        let mut ans = 1 << 60;
        for i in 0..self.n {
            let c = self.initial_colors[i];
            let nret = self.dfs(0, c, i, i);
            ans = std::cmp::min(ans, nret);
        }
        println!("{}", ans);
    }
}

fn main() {
    let mut solver = Solver::new();
    solver.solve();
}