// 진입전에 토글 된 상태로 주고, 합은 일단 합치고.
// 마무리만 어떻게 잘하면 되는데... 음.
// 여기서 마무리 단계에서는 다시 돌아올 필요가 없으니까.
// 어디서 빠져나오는 시간이 가장 긴 두 곳을 시작과 마지막으로 삼을 필요가 있다.
// 돌아오는 데에 시간을 주는데. 음 디피값을 저장을 하고 min처리를 할까?
// 이 섭트리를 칠하기만 하는 데에 필요한 비용과 그 비용이 가장 큰 두곳에서 시작해야 하는데.
// 그러면... 음 그냥 시작점을 두 곳으로 잡고. 그러한 곳을 2번 사용하면 될꺼 같은데.
// 다 한번씩 해줄 수는 없는데.
// 트리의 지름..?
// 어느 점을 기준으로 이 값을 구해줬다면 dfs를 돌리면서 다른데서도 구해줄 수 있을까?
// 두 개의 줄기를 공짜로 쓴다.
// 시작지점은 ... 음
// 가는 엣지랑 백엣지.
// 남은 것의 개수와. 이 곳이 채택되었는지의 여부.
// 음... 현재 두개가 남았다면. 11로 던져주는 행동에 대해서. 그리디를 쓸 수 있을까?
// 11로 던져준다. 2로 던져준다.
// 11로 던져주는 행위에 대해서는 어떻게 하지?
// 음... 1로 던진거와 0으로 던진 게 있을 때, 그 차이가 가장 큰 2개를 뽑으면 되지 않을까?
// 2로 던져주는 건 그냥 던지면 되고.


// 난 다시 돌아와야 한다. 모든 간선에서.
// 이렇게 했을 때, pii로 받아야지.
// 음... 이 행동에 대한 결과는 정해져 있다.
// 1로 던졌다면 돌아오지 않는다는 뜻이므로 그냥 거기서 만들어주면 되고.
// 0으로 던졌다면 다시 돌아와야 한다. white개수. 를 미리 구해놔.
// 만약에 0이라면 white번만큼 토글되고 돌아오므로, 

#include <cstdio>
#include <memory.h>
#include <cstring>
#include <vector>
#include <deque>
#include <cstdlib>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cassert>
#include <functional>
#include <iostream>
#include <set>
#include <list>
#include <map>
#include <time.h>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
using namespace std;

typedef unsigned long long llu;
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<int, pii> piii;
typedef pair<ll, ll> pll;
typedef pair<ll, int> pli;
typedef pair<int, ll> pil;
typedef pair<string, int> psi;
const ll MOD = 1e9 + 7;
const long double PI = 3.141592653589793238462643383279502884197;

priority_queue<int, vector<int>, greater<int> > pq;
vector<int> v[100000];

char col[100000];
int rotn[100000];
int dp[100000][3];

// 1. 블랙이 아닌 루트를 하나 임의로 구한다.
// 2. 그걸 루트로 했을 때, 각 자식의 화이트 개수를 구한다.
// 3. 그게 1이면 멈출 수 있다는 의미이며, 0인 정점으로는 이동하지 않는다.
// 4. 이제 선택된 루트로부터 내릴 수 있는 자식수가 1인 것과 2인 것으로 각각 DP를 돌린다.

int fs(int o, int pa) {
	int sum = col[o];
	for (int i = 0; i < sz(v[o]); i++)
		if (v[o][i] != pa)
			sum += fs(v[o][i], o);

	return rotn[o] = sum;
}

// st개 만큼 줄기를 가지고 있음.
// 0과 2는 줄기에 포함이 안되는 부분.
// 만약 2를 나누는 부분인 경우에는. 이 정점을 포함해서 1인것과 같으므로...
// 도달하는 순간 색이 바뀜.

int go(int o, int pa, int st) {
	if (dp[o][st] != -1) return dp[o][st];

	int t = col[o];
	int mav = 0, sum = 0, miv = 1e9;

	if (st == 0) {
		for (int i = 0; i < sz(v[o]); i++) {
			if (rotn[v[o][i]]) {
				t ^= 1;
				if (v[o][i] == pa) continue;
				sum += go(v[o][i], o, 0) + 2;
			}
		}

		return dp[o][st] = sum + t;
	}
	else if (st == 1) {
		int flag = 0;
		for (int i = 0; i < sz(v[o]); i++) {
			if (rotn[v[o][i]]) {
				t ^= 1;
				if (v[o][i] == pa) continue;
				flag = 1;
				sum += go(v[o][i], o, 0) + 2;
				mav = max(mav, go(v[o][i], o, 0) - go(v[o][i], o, 1) + 1);
			}
		}

		return dp[o][st] = sum - mav + (t ^ flag);
	}
	else {
		int flag = 0;
		for (int i = 0; i < sz(v[o]); i++) {
			if (rotn[v[o][i]]) {
				t ^= 1;
				if (v[o][i] == pa) continue;
				sum += go(v[o][i], o, 0) + 2;
				mav = max(mav, go(v[o][i], o, 0) - go(v[o][i], o, 2));
			}
		}
		miv = sum - mav + t;

		vector<int> ma;
		sum = 0; t = col[o];
		for (int i = 0; i < sz(v[o]); i++) {
			if (rotn[v[o][i]]) {
				t ^= 1;
				if (v[o][i] == pa) continue;
				sum += go(v[o][i], o, 0) + 2;
				ma.push_back(go(v[o][i], o, 0) - go(v[o][i], o, 1) + 1);
			}
		}
		sort(all(ma), greater<int>());
		if (sz(ma) >= 2) {
			sum -= ma[0] + ma[1] - 1;
			miv = min(miv, sum + (t ^ 1));
		}

		return dp[o][st] = miv;
	}
}

int main() {
	memset(dp, -1, sizeof(dp));
	int n, st = -1;
	scanf("%d", &n);

	int a, b;
	for (int i = 1; i < n; i++) {
		scanf("%d %d", &a, &b);
		a--; b--;
		v[a].push_back(b);
		v[b].push_back(a);
	}

	for (int i = 0; i < n; i++) {
		scanf(" %c", &col[i]);
		if (col[i] == 'W') {
			col[i] = 1;
			st = i;
		}
		else col[i] = 0;
	}
	fs(st, st);

	if (st == -1) return !printf("0");
	printf("%d", min(go(st, st, 1), go(st, st, 2)));
}

Measured memory_bytes: 23040