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



Sample input:
5
1 2
2 3
2 4
4 5
WBBWW


Sample output:
5

Submission status: Wrong Answer

Solution code:
import sys
from collections import deque

input=sys.stdin.readline

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

c=input()[:N]

deg=[len(edge[i]) for i in range(N)]
leaf=set([])
for i in range(N):
    if deg[i]==1 and c[i]=="B":
        leaf.add(i)

ban=set([])
while leaf:
    v=leaf.pop()
    ban.add(v)
    deg[v]=0
    for nv in edge[v]:
        deg[nv]-=1
        if deg[nv]==1 and c[nv]=="B":
            leaf.add(nv)

for i in range(N):
    edge[i]=[nv for nv in edge[i] if nv not in ban]

root=-1
for i in range(N):
    if i not in ban:
        root=i

parent=[-2]*N
deq=deque([(root,-1)])
node=[]
while deq:
    v,pv=deq.popleft()
    parent[v]=pv
    node.append(v)
    for nv in edge[v]:
        if nv!=pv:
            deq.append((nv,v))

node=node[::-1]

for i in range(N):
    edge[i]=[nv for nv in edge[i] if nv!=parent[i]]

check=True
for i in range(N):
    check&=(deg[i]<=0)
if check:
    print(int(c[root]=="W"))
    exit()

cond=[0]*N
for v in range(N):
    if (deg[v]%2==1 and c[v]=="B") or (deg[v]%2==0 and c[v]=="W"):
        cond[v]+=1
    else:
        cond[v]-=1

lower=[0]*N
for v in node:
    res=0
    for nv in edge[v]:
        res=max(res,lower[nv])
    res+=1+cond[v]
    lower[v]=res

upper=[0]*N
for v in node:
    n=len(edge[v])
    if n>1:
        left=[0]*n
        right=[0]*n
        for i in range(n-1):
            nv=edge[v][i]
            left[i]=max(left[i-1],lower[nv]+2+cond[v])
        nv=edge[v][-1]
        upper[nv]=left[n-2]+cond[nv]
        right[n-1]=lower[nv]+2+cond[v]
        for i in range(n-2,0,-1):
            nv=edge[v][i]
            upper[nv]=max(left[i-1],right[i+1])+cond[nv]
            right[i]=max(right[i+1],lower[nv]+2+cond[v])
        if edge[v][0]!=pv:
            nv=edge[v][0]
            upper[nv]=right[1]+cond[nv]
    if v!=root:
        for nv in edge[v]:
            upper[nv]=max(upper[nv],upper[v]+1+cond[nv])

base=sum(deg[i] for i in range(N))+sum(cond[i]==1 for i in range(N))
#print(deg)
#print(base)
#print(lower)
#print(upper)
#print(base)
print(base-max(max(upper),max(lower)))

Submission status: Wrong Answer

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

N = int(readline())
data = read().split()
m = map(int,data[:-1])
XY = zip(m,m)
C = [0] + [1 * (x == ord('W')) for x in data[-1]]

graph = [set() for _ in range(N+1)]
for x,y in XY:
    graph[x].add(y)
    graph[y].add(x)

deg = [len(x) for x in graph]
b_leaf = [i for i in range(N+1) if deg[i] == 1 and not C[i]]

while b_leaf:
    x = b_leaf.pop()
    for y in graph[x]:
        graph[y].remove(x)
        deg[y] -= 1
        if deg[y] == 1 and not C[y]:
            b_leaf.append(y)
    deg[x] = 0
    graph[x].clear()

V = set(i for i,E in enumerate(graph) if E)
if len(V) <= 2:
    print(len(V))
    exit()
root = None
for v in V:
    if deg[v] > 1:
        root = v
        break

parent = [0] * (N+1)
order = []
stack = [root]
while stack:
    x = stack.pop()
    order.append(x)
    for y in graph[x]:
        if y == parent[x]:
            continue
        parent[y] = x
        stack.append(y)

"""
・Euler tourの状態から、パスをひとつ除く
・葉と葉を結ぶとしてよい。通ると2コスト安くなる点がある
"""

for i in range(N+1):
    C[i] ^= (1&deg[i])

cost_full = sum(deg) + sum(C)

# C[i] == 1 となる i を最もたくさん含むパスを探す

opt = 0
dp = [0] * (N+1)
for v in order[::-1]:
    if deg[v] == 1:
        continue
    arr = sorted((dp[w] for w in graph[v] if w != parent[v]),reverse = True) + [0]
    x = arr[0] + arr[1] + C[v]
    if opt < x:
        opt = x
    dp[v] = arr[0] + C[v]

answer = cost_full - 2 * opt
print(answer)

Submission status: Wrong Answer

Solution code:
input = __import__('sys').stdin.readline
MIS = lambda: map(int,input().split())

n = int(input())
adj = [set() for i in range(n+1)]
white = [False]
for i in range(n-1):
    a, b = MIS()
    adj[a].add(b); adj[b].add(a)
s = input().rstrip()
for i in range(n): white.append(s[i] == 'W')

# Corner cases
if sum(white) <= 1: print(sum(white)); exit()

# Remove black leaves
stack = [i for i in range(1,n+1) if len(adj[i]) == 1 and not white[i]]
while stack:
    p = stack.pop()
    pa = min(adj[p])
    adj[pa].remove(p); adj[p].clear()
    if len(adj[pa]) == 1 and not white[pa]: stack.append(pa)

# Simulate Euler tour
root = 1
while not adj[root]: root+= 1
tadj = [[] for i in range(n+1)]
vis = [False]*(n+1); vis[root] = True
stack = [root]
while stack:
    p = stack.pop()
    for q in adj[p]:
        if vis[q]: continue
        vis[q] = True; tadj[p].append(q)
        stack.append(q)
for i in range(1, n+1):
    if adj[i] and len(tadj[i])%2 == 0: white[i] = not white[i]
white[root] = not white[root]

# Diameter
def bfs(v):
    stack = [v]
    dist = [-1]*(n+1); dist[v] = white[v]
    while stack:
        p = stack.pop()
        for q in adj[p]:
            if dist[q] != -1: continue
            dist[q] = dist[p] + white[q]
            stack.append(q)
    return dist

numedge = sum(map(len, adj))
d1 = bfs(root)
u = d1.index(max(d1))
d2 = bfs(u)
diam = max(d2)
print(numedge - diam)

Submission status: Wrong Answer

Solution code:
from collections import deque


def first_cut(links, colors):
    tmp_links = links.copy()
    for v, neighbors in tmp_links.items():
        while len(neighbors) == 1 and colors[v]:
            del links[v]
            par = neighbors.pop()
            links[par].remove(v)
            v = par
            neighbors = links[par]
    return links


def diameter(links):
    flags = {v: colors[v] ^ (len(link) % 2 == 0) for v, link in links.items()}

    s = next(iter(links))
    fs = flags[s]
    v, d = 0, 0
    q = deque(sorted((fs + flags[v], v, s) for v in links[s]))
    while q:
        d, v, a = q.popleft()
        for u in links[v]:
            if u == a:
                continue
            fu = flags[u]
            if fu:
                q.append((d + 1, u, v))
            else:
                q.appendleft((d, u, v))
    t = v
    ft = flags[t]
    q = deque(sorted((ft + flags[v], v, t) for v in links[s]))
    while q:
        d, v, a = q.popleft()
        for u in links[v]:
            if u == a:
                continue
            fu = flags[u]
            if fu:
                q.append((d + 1, u, v))
            else:
                q.appendleft((d, u, v))
    return d


def solve(links, colors):
    if all(colors):
        return 0
    if sum(colors) == len(colors) - 1:
        return 1

    links = first_cut(links, colors)
    k = len(links)

    euler_tour = 2 * (k - 1) + sum(colors[v] ^ (len(link) % 2 == 0) for v, link in links.items())
    return euler_tour - 2 * diameter(links)


n = int(input())
links = {i: set() for i in range(n)}
for _ in range(n - 1):
    x, y = map(int, input().split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)
colors = [c == 'B' for c in input()]

print(solve(links, colors))

Submission status: Wrong Answer

Solution code:
def first_cut(links, colors):
    tmp_links = links.copy()
    for v, neighbors in tmp_links.items():
        while len(neighbors) == 1 and colors[v]:
            del links[v]
            par = neighbors.pop()
            links[par].remove(v)
            v = par
            neighbors = links[par]
    return links


def solve(links, colors):
    ans = 0
    if all(colors):
        return 0

    links = first_cut(links, colors)

    while True:
        if len(links) == 1:
            col = [colors[i] for i in links][0]
            if col:
                pass
            else:
                ans -= 1
            return ans
        if len(links) == 2:
            col = [colors[i] for i in links]
            if all(col):
                pass
            elif any(col):
                ans += 1
            else:
                ans += 2
            return ans

        tmp_links = links.copy()

        for v, neighbors in tmp_links.items():
            if len(neighbors) > 1 or not neighbors:
                continue
            if colors[v]:
                ans += 1
            else:
                ans += 2
            par = neighbors.pop()
            colors[par] ^= 1
            links[par].remove(v)
            del links[v]


n = int(input())
links = {i: set() for i in range(n)}
for _ in range(n - 1):
    x, y = map(int, input().split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)
colors = [c == 'B' for c in input()]

print(solve(links, colors))

Submission status: Wrong Answer

Solution code:
def first_cut(links, colors):
    tmp_links = links.copy()
    for v, neighbors in tmp_links.items():
        while len(neighbors) == 1 and colors[v]:
            del links[v]
            par = neighbors.pop()
            links[par].remove(v)
            v = par
            neighbors = links[par]
    return links


def solve(links, colors):
    ans = 0
    if all(colors):
        return 0

    print(links)
    links = first_cut(links, colors)
    print(links)

    while True:
        if len(links) == 1:
            col = [colors[i] for i in links][0]
            if col:
                pass
            else:
                ans -= 1
            return ans
        if len(links) == 2:
            col = [colors[i] for i in links]
            if all(col):
                pass
            elif any(col):
                ans += 1
            else:
                ans += 2
            return ans

        tmp_links = links.copy()

        for v, neighbors in tmp_links.items():
            if len(neighbors) > 1 or not neighbors:
                continue
            if colors[v]:
                ans += 1
            else:
                ans += 2
            par = neighbors.pop()
            colors[par] ^= 1
            links[par].remove(v)
            del links[v]


n = int(input())
links = {i: set() for i in range(n)}
for _ in range(n - 1):
    x, y = map(int, input().split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)
colors = [c == 'B' for c in input()]

print(solve(links, colors))

Submission status: Time Limit Exceeded

Solution code:

"""

https://atcoder.jp/contests/arc097/tasks/arc097_d

始点と終点関係ある？
→逆にしても問題はない

黒い葉は完全に無視できる(落とせる)
よって、葉はすべて白
葉以外は白黒どっちもあり得る

すべての葉をめぐる最短経路？
ある葉からスタートするのは自明っぽい？
ある白からスタートするのはそう

→自分を塗ってからdfsする
→全方位木dp?

行きのみで帰らない場所が1つ存在するはず
→始点と終点のパスとそこから生える木って感じのイメージ

足踏み(停止)の回数を極力少なくしたい
→始点でも終点でもない場合、 e本の辺がつながってたらe回訪問は確定
　e^colorが黒でない場合は+1
→つまり、各頂点で消費する回数は始点・終点でない限り常に一定？

終点はまず葉→始点も葉でおｋ
始点は足踏みなので1秒つかう　終点も1秒使う
パス上の点は、e-1回訪問(ここが根本的に違う！)

つまり、あるパスがあって　その長さがL(両端除く)の時、最大でL減る
ただし、パス上にあっても回数が減らない点もある

B=0 W=1とするか
(color^E) == 1 の点は、E-1回訪問になると足踏みがいらないから2減る
つまり、そのような点が最大数あるパスを求めればいい

"""

import sys
sys.setrecursionlimit(200000)
from collections import deque

MM = 0

def dfs(v,p):
    global MM

    if v != p and linknum[v] == 1:
        return 0

    cl = []
    for nex in lis[v]:
        if nex != p and exist[nex]:
            tmp = dfs(nex,v)
            cl.append(tmp)
    cl.sort()
    cl.reverse()

    if len(cl) == 1:
        MM = max(MM , cl[0])
    else:
        if (linknum[v]+c[v])%2 == 1:
            MM = max(MM , cl[0] + cl[1] + 2)
        else:
            MM = max(MM , cl[0] + cl[1])

    
    if (linknum[v]+c[v]) % 2 == 1:
        return cl[0]+ 2
    else:
        return cl[0]

N = int(input())

lis =  [ [] for i in range(N) ]
linknum = [0] * N
for i in range(N-1):
    u,v = map(int,input().split())
    u -= 1
    v -= 1

    lis[u].append(v)
    lis[v].append(u)
    linknum[u] += 1
    linknum[v] += 1

ctmp = input()
c = []

for i in ctmp:
    if i == "B":
        c.append(0)
    else:
        c.append(1)

exist = [True] * N

q = deque([])
for i in range(N):
    if linknum[i] <= 1 and c[i] == 0:
        q.append(i)

while len(q) > 0:
    now = q.popleft()
    exist[now] = False
    linknum[now] = 0
    
    for nex in lis[now]:
        linknum[nex] -= 1

        if linknum[nex] == 1 and c[nex] == 0:
            q.append(nex)

#print (exist)
start = None
for i in range(N):
    if exist[i]:
        start = i
        break
else:
    print (0)
    sys.exit()

if linknum[start] == 0:
    print (1)
    sys.exit()

ans = 0
#print (linknum)
for i in range(N):
    if exist[i]:

        if (linknum[i] + c[i]) % 2 == 0:
            ans += linknum[i]
        else:
            ans += linknum[i] + 1

MM = 0
pick = dfs(start,start)
print (ans - MM)

Submission status: Accepted

Solution code:
import sys
from collections import deque

input=sys.stdin.readline

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

c=input()[:N]

deg=[len(edge[i]) for i in range(N)]
leaf=set([])
for i in range(N):
    if deg[i]==1 and c[i]=="B":
        leaf.add(i)

ban=set([])
while leaf:
    v=leaf.pop()
    ban.add(v)
    deg[v]=0
    for nv in edge[v]:
        deg[nv]-=1
        if deg[nv]==1 and c[nv]=="B":
            leaf.add(nv)

for i in range(N):
    edge[i]=[nv for nv in edge[i] if nv not in ban]

root=-1
for i in range(N):
    if i not in ban:
        root=i

parent=[-2]*N
deq=deque([(root,-1)])
node=[]
while deq:
    v,pv=deq.popleft()
    parent[v]=pv
    node.append(v)
    for nv in edge[v]:
        if nv!=pv:
            deq.append((nv,v))

node=node[::-1]

for i in range(N):
    edge[i]=[nv for nv in edge[i] if nv!=parent[i]]

check=True
for i in range(N):
    check&=(deg[i]<=0)
if check:
    print(int(c[root]=="W"))
    exit()

cond=[0]*N
for v in range(N):
    if (deg[v]%2==1 and c[v]=="B") or (deg[v]%2==0 and c[v]=="W"):
        cond[v]+=1
    else:
        cond[v]-=1

lower=[0]*N
for v in node:
    res=0
    for nv in edge[v]:
        res=max(res,lower[nv])
    res+=1+cond[v]
    lower[v]=res

upper=[0]*N
node=node[::-1]
for v in node:
    n=len(edge[v])
    if n>1:
        left=[0]*n
        right=[0]*n
        for i in range(n-1):
            nv=edge[v][i]
            left[i]=max(left[i-1],lower[nv]+2+cond[v])
        nv=edge[v][-1]
        upper[nv]=left[n-2]+cond[nv]
        right[n-1]=lower[nv]+2+cond[v]
        for i in range(n-2,0,-1):
            nv=edge[v][i]
            upper[nv]=max(left[i-1],right[i+1])+cond[nv]
            right[i]=max(right[i+1],lower[nv]+2+cond[v])
        if edge[v][0]!=pv:
            nv=edge[v][0]
            upper[nv]=right[1]+cond[nv]
    if v!=root:
        for nv in edge[v]:
            upper[nv]=max(upper[nv],upper[v]+1+cond[nv])

base=sum(deg[i] for i in range(N))+sum(cond[i]==1 for i in range(N))
#print(deg)
#print(base)
#print(lower)
#print(upper)
#print(base)
print(base-max(max(upper),max(lower)))

Submission status: Accepted

Solution code:
import sys
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

N = int(readline())
data = read().split()
m = map(int,data[:-1])
XY = zip(m,m)
C = [0] + [1 * (x == ord('W')) for x in data[-1]]

graph = [set() for _ in range(N+1)]
for x,y in XY:
    graph[x].add(y)
    graph[y].add(x)

deg = [len(x) for x in graph]
b_leaf = [i for i in range(N+1) if deg[i] == 1 and not C[i]]

while b_leaf:
    x = b_leaf.pop()
    for y in graph[x]:
        graph[y].remove(x)
        deg[y] -= 1
        if deg[y] == 1 and not C[y]:
            b_leaf.append(y)
    deg[x] = 0
    graph[x].clear()

V = set(i for i,E in enumerate(graph) if E)
if len(V) <= 2:
    print(sum(C))
    exit()
root = None
for v in V:
    if deg[v] > 1:
        root = v
        break

parent = [0] * (N+1)
order = []
stack = [root]
while stack:
    x = stack.pop()
    order.append(x)
    for y in graph[x]:
        if y == parent[x]:
            continue
        parent[y] = x
        stack.append(y)

"""
・Euler tourの状態から、パスをひとつ除く
・葉と葉を結ぶとしてよい。通ると2コスト安くなる点がある
"""

for i in range(N+1):
    C[i] ^= (1&deg[i])

cost_full = sum(deg) + sum(C)

# C[i] == 1 となる i を最もたくさん含むパスを探す

opt = 0
dp = [0] * (N+1)
for v in order[::-1]:
    if deg[v] == 1:
        continue
    arr = sorted((dp[w] for w in graph[v] if w != parent[v]),reverse = True) + [0]
    x = arr[0] + arr[1] + C[v]
    if opt < x:
        opt = x
    dp[v] = arr[0] + C[v]

answer = cost_full - 2 * opt
print(answer)

Submission status: Accepted

Solution code:
input = __import__('sys').stdin.readline
MIS = lambda: map(int,input().split())
range = xrange

n = int(input())
adj = [set() for i in range(n+1)]
white = [False]
for i in range(n-1):
    a, b = MIS()
    adj[a].add(b); adj[b].add(a)
s = input().rstrip()
for i in range(n): white.append(s[i] == 'W')

# Corner cases
if sum(white) <= 1: print(sum(white)); exit()

# Remove black leaves
stack = [i for i in range(1,n+1) if len(adj[i]) == 1 and not white[i]]
while stack:
    p = stack.pop()
    pa = min(adj[p])
    adj[pa].remove(p); adj[p].clear()
    if len(adj[pa]) == 1 and not white[pa]: stack.append(pa)

# Simulate Euler tour
root = 1
while not adj[root]: root+= 1
tadj = [[] for i in range(n+1)]
vis = [False]*(n+1); vis[root] = True
stack = [root]
while stack:
    p = stack.pop()
    for q in adj[p]:
        if vis[q]: continue
        vis[q] = True; tadj[p].append(q)
        stack.append(q)
for i in range(1, n+1):
    if adj[i] and len(tadj[i])%2 == 0: white[i] = not white[i]
white[root] = not white[root]

# Diameter
def bfs(v):
    stack = [v]
    dist = [-1]*(n+1); dist[v] = white[v]
    while stack:
        p = stack.pop()
        for q in adj[p]:
            if dist[q] != -1: continue
            dist[q] = dist[p] + white[q]
            stack.append(q)
    return dist

basecost = sum(map(len, adj)) + sum(white)
d1 = bfs(root)
diam = max(bfs(d1.index(max(d1))))
print(basecost - 2*diam)

Submission status: Accepted

Solution code:
from collections import deque


def first_cut(links, colors):
    tmp_links = links.copy()
    for v, neighbors in tmp_links.items():
        while len(neighbors) == 1 and colors[v]:
            del links[v]
            par = neighbors.pop()
            links[par].remove(v)
            v = par
            neighbors = links[par]
    return links


def diameter(links, flags):
    def dfs(s):
        fs = flags[s]
        d, v = 0, 0
        q = deque(sorted((fs + flags[v], v, s) for v in links[s]))
        while q:
            d, v, a = q.popleft()
            for u in links[v]:
                if u == a:
                    continue
                fu = flags[u]
                if fu:
                    q.append((d + 1, u, v))
                else:
                    q.appendleft((d, u, v))
        return d, v

    s = next(iter(links))
    _, t = dfs(s)
    d, _ = dfs(t)
    return d


def solve(links, colors):
    if all(colors):
        return 0

    links = first_cut(links, colors)
    k = len(links)

    if k == 1:
        return 1

    flags = {v: colors[v] ^ (len(link) % 2 == 0) for v, link in links.items()}
    euler_tour = 2 * (k - 1) + sum(flags.values())
    return euler_tour - 2 * diameter(links, flags)


n = int(input())
links = {i: set() for i in range(n)}
for _ in range(n - 1):
    x, y = map(int, input().split())
    x -= 1
    y -= 1
    links[x].add(y)
    links[y].add(x)
colors = [c == 'B' for c in input()]

print(solve(links, colors))

Submission status: Runtime Error

Solution code:
import sys

input=sys.stdin.readline
sys.setrecursionlimit(10**5)

N=int(input())
edge=[[] for i in range(N)]
for i in range(N-1):
    x,y=map(int,input().split())
    edge[x-1].append(y-1)
    edge[y-1].append(x-1)

c=input()[:N]

deg=[len(edge[i]) for i in range(N)]
leaf=set([])
for i in range(N):
    if deg[i]==1 and c[i]=="B":
        leaf.add(i)

ban=set([])
while leaf:
    v=leaf.pop()
    ban.add(v)
    deg[v]=0
    for nv in edge[v]:
        deg[nv]-=1
        if deg[nv]==1 and c[nv]=="B":
            leaf.add(nv)

for i in range(N):
    edge[i]=[nv for nv in edge[i] if nv not in ban]

root=-1
for i in range(N):
    if i not in ban:
        root=i

check=True
for i in range(N):
    check&=(deg[i]==0)
if check:
    print(int(c[root]=="W"))
    exit()

cond=[0]*N
for v in range(N):
    if (deg[v]%2==1 and c[v]=="B") or (deg[v]%2==0 and c[v]=="W"):
        cond[v]+=1
    else:
        cond[v]-=1

lower=[0]*N
def lower_dfs(v,pv):
    res=0
    for nv in edge[v]:
        if nv!=pv:
            lower_dfs(nv,v)
            res=max(res,lower[nv])
    res+=1+cond[v]
    lower[v]=res

lower_dfs(root,-1)

upper=[0]*N
def upper_dfs(v,pv):
    n=len(edge[v])
    left=[0]*n
    right=[0]*n
    for i in range(n-1):
        nv=edge[v][i]
        if nv!=pv:
            left[i]=max(left[i-1],lower[nv]+2+cond[v])
        else:
            left[i]=left[i-1]
    if edge[v][-1]!=pv:
        nv=edge[v][-1]
        upper[nv]=left[n-2]+cond[nv]
        right[n-1]=lower[nv]+2+cond[v]
    for i in range(n-2,0,-1):
        nv=edge[v][i]
        if nv!=pv:
            upper[nv]=max(left[i-1],right[i+1])+cond[nv]
            right[i]=max(right[i+1],lower[nv]+2+cond[v])
        else:
            right[i]=right[i+1]
    if n!=1:
        if edge[v][0]!=pv:
            nv=edge[v][0]
            upper[nv]=right[1]+cond[nv]

    if v!=root:
        for nv in edge[v]:
            if nv!=pv:
                upper[nv]=max(upper[nv],upper[v]+1+cond[nv])
    for nv in edge[v]:
        if nv!=pv:
            upper_dfs(nv,v)

upper_dfs(root,-1)

base=sum(deg[i] for i in range(N))+sum(cond[i]==1 for i in range(N))
#print(deg)
#print(base)
#print(lower)
#print(upper)
#print(base)
print(base-max(max(upper),max(lower)))

Submission status: Runtime Error

Solution code:
#!/usr/bin/env python3


def dfs(v, r, adj_list, c, visited):

    visited[v] = True

    ts = []
    tp = 0
    wc = 0
    for w in adj_list[v]:
        if visited[w]:
            continue
        t, p = dfs(w, r, adj_list, c, visited)
        if t != 0:
            ts.append(t - p)
            tp += p
            wc += 1

    if wc == 0:
        if c[v] == 'W':
            return 1, 2
        else:
            return 0, 0

    ts.sort()

    if v == r:
        if wc == 1:
            t = tp + ts[0] + 1
            return t, t
        else:
            t = tp + ts[0] + ts[1] + 1 + (wc % 2)
            return t, t

    if c[v] == 'W':
        t = tp + ts[0] + 1 + (wc + 1) % 2
        p = tp + 2 + wc % 2
        return t, p
    else:
        t = tp + ts[0] + 1 + wc % 2
        p = tp + 2 + (wc + 1) % 2
        return t, p


def solve(n, adj_list, c):

    v = c.find('W')
    if v < 0:
        return 0

    visited = [False] * n
    ans, _ = dfs(v, v, adj_list, c, visited)

    return ans


def main():
    n = input()
    n = int(n)
    adj_list = [[] for _ in range(n)]
    for _ in range(n - 1):
        x, y = input().split()
        x = int(x) - 1
        y = int(y) - 1
        adj_list[x].append(y)
        adj_list[y].append(x)
    c = input()

    print(solve(n, adj_list, c))


if __name__ == '__main__':
    main()

Submission status: Runtime Error

Solution code:
#!/usr/bin/env python3

memo = {}

def dfs(v, adj_list, c, visited):

    visited[v] = True
    rs = []
    ds = []
    td = 0
    wc = 0
    for w in adj_list[v]:
        if visited[w]:
            continue
        if (v, w) in memo:
            r, d = memo[(v, w)]
        else:
            r, d = dfs(w, adj_list, c, visited)
            if r != 0:
                r += 1
                d += 2
            memo[(v, w)] = (r, d)
        if r != 0:
            rs.append(r)
            ds.append(d)
            td += d
            wc += 1

    r_min = 0
    if td:
        r_min = td - ds[0] + rs[0]
        for i in range(1, wc):
            r_min = min(r_min, td - ds[i] + rs[i])

    if c[v] == 'W':
        r_min += (wc + 1) % 2
        td += wc % 2
    else:
        r_min += wc % 2
        td += (wc + 1) % 2


    return r_min, td


def solve(n, adj_list, c):

    ans = 10 ** 10
    for v in range(n):
        visited = [False] * n
        r, _ = dfs(v, adj_list, c, visited)
        ans = min(ans, r)

    return ans


def main():
    n = input()
    n = int(n)
    adj_list = [[] for _ in range(n)]
    for _ in range(n - 1):
        x, y = input().split()
        x = int(x) - 1
        y = int(y) - 1
        adj_list[x].append(y)
        adj_list[y].append(x)
    c = input()

    print(solve(n, adj_list, c))


if __name__ == '__main__':
    main()

Submission status: Runtime Error

Solution code:
#include "bits/stdc++.h"
using namespace std;
template<typename T> class segment_tree{
private:
    static const int default_size = 1;
    int my_size;
    vector<T> tree;
    void build(vector<T> & data, int id, int l, int r){
        if(l == r) tree[id] = data[l];
        else{
            int mid = (l + r)>>1;
            build(data, id + id, l, mid);
            build(data, id + id + 1, mid + 1, r);
            tree[id] = tree[id + id] + tree[id + id + 1];
        }
    }
    void update(int id, int l, int r, int pos, T v){
        if(l == r) tree[id] = v;
        else{
            int mid = (l + r)>>1;
            if(pos <= mid) update(id + id, l, mid, pos, v);
            else update(id + id + 1, mid + 1, r, pos, v);
            tree[id] = tree[id + id] + tree[id + id + 1];
        }
    }
    T query(int id, int l, int r, int x, int y){
        if(l > y || r < x) return T();
        if(x <= l && r <= y) return tree[id];
        int mid = (l + r)>>1;
        return query(id + id, l, mid, x, y) + query(id + id + 1, mid + 1, r, x, y);
    }
public:
    segment_tree(){
        my_size = default_size;
        clear();
    }
    segment_tree(int size){
        my_size = size;
        clear();
    }
    void clear(){
        // Important
        tree.assign(my_size * 4, T());
    }
    void build(vector<T> & data){
        assert(data.size() <= my_size);
        data.resize(my_size);
        build(data, 1, 0, my_size-1);
    }
    void setPos(int pos, T value){
        assert(pos >= 0 && pos <= my_size - 1);
        update(1, 0, my_size - 1, pos, value);
    }
    T getPos(int pos){
        assert(pos >= 0 && pos <= my_size - 1);
        return query(1, 0, my_size - 1, pos, pos);
    }
    void addToPos(int pos, T value){
        assert(pos >= 0 && pos <= my_size - 1);
        setPos(pos, getPos(pos) + value);
    }
    T getInterval(int l, int r){
        assert(l <= r);
        assert(r <= my_size - 1);
        return query(1, 0, my_size - 1, l, r);
    }
	T getFull(){
		return tree[1];
	}
};
struct valt{
	long long p0, p1, sum1, mdiff;
	valt(){
		p0 = 0;
		p1 = 0;
		sum1 = 0;
		mdiff = 0;
	}
	valt(long long a, long long b){
		p0 = a; p1 = b;
		sum1 = p1;
		mdiff = p1 - p0;
	}
	valt operator + (valt other){
		valt ans;
		ans.sum1 = sum1 + other.sum1;
		ans.mdiff = max(mdiff, other.mdiff);
		return ans;
	}
};
using tree = segment_tree<valt>;
const int maxn = 100100;
vector<int> tr[maxn];
tree mtree[maxn];
char s[maxn];
int ty[maxn], ms[maxn];
long long d[2][maxn];
void add(int cur, int vert, valt val){
	int pos = lower_bound(tr[cur].begin(), tr[cur].end(), vert) - tr[cur].begin();
	mtree[cur].setPos(pos, val);
}
void rem(int cur, int vert){
	int pos = lower_bound(tr[cur].begin(), tr[cur].end(), vert) - tr[cur].begin();
	mtree[cur].setPos(pos, valt());
}
void calc(int cur, int par, int sons){
	int ru = par != -1;
	int letdown = max(sons - 1, 0);
	valt incur = mtree[cur].getFull();
	d[0][cur] = sons + letdown + incur.sum1 - incur.mdiff + ((ty[cur] + letdown + ru)%2);
	d[1][cur] = 2 * sons + incur.sum1 + ((ty[cur] + sons + ru)%2);
}
void solve(int cur, int par){
	int sons = 0;
	for(int nxt : tr[cur]){
		if(nxt == par) {
			continue;
		}
		solve(nxt, cur);
		valt pnxt = valt(d[0][nxt], d[1][nxt]);
		add(cur, nxt, pnxt);
		sons++;
	}
	ms[cur] = sons;
	calc(cur, par, sons);
}
void fix(int cur, int par){
	if(par != -1){
		valt before = valt(d[0][cur], d[1][cur]);

		rem(par, cur);
		calc(par, cur, tr[par].size() - 1);

		add(cur, par, valt(d[0][par], d[1][par]));
		calc(cur, -1, tr[cur].size());

		add(par, cur, before);

		calc(par, -1, tr[par].size());
	}
	for(int nxt : tr[cur]){
		if(nxt == par) continue;
		fix(nxt, cur);
	}
}
int deg[maxn];
set<int> pk[maxn], stl;
int main(){
	int n;
	scanf("%d", &n);
	for(int e = 0; e < n - 1; e++){
		int x, y; scanf("%d %d", &x, &y); x--; y--;
		pk[x].insert(y);
		pk[y].insert(x);
		deg[x]++; deg[y]++;
	}
	scanf("%s", s);
	for(int e = 0; e < n; e++) ty[e] = s[e] == 'W';
	queue<int> q;
	for(int e = 0; e < n; e++) stl.insert(e);
	for(int e = 0; e < n; e++) if(deg[e] == 1 && ty[e] == 0) q.push(e);
	while(!q.empty()){
		int u = q.front(); q.pop();
		stl.erase(u);
		for(int v : pk[u]){
			deg[v]--;
			pk[v].erase(u);
			if(deg[v] == 1 && ty[v] == 0) q.push(v);
		}
		pk[u].clear();
	}
	if(stl.empty()){
		cout << 0 << endl;
		return 0;
	}
	int rt = *(stl.begin());
	for(int v : stl){
		for(int u : pk[v]){
			tr[v].push_back(u);
		}
	}
	for(int e : stl) mtree[e] = tree(tr[e].size() + 100);
	solve(rt, -1);
	// cerr << "before" << endl;
	// for(int e = 0; e < n; e++) cerr << d[0][e] << " " << d[1][e] << endl;
	fix(rt, -1);
	// cerr << "after" << endl;
	// for(int e = 0; e < n; e++) cerr << d[0][e] << " " << d[1][e] << endl;
	long long ans = 1ll<<60;
	for(int v : stl) ans = min(ans, d[0][v]);
	cout << ans << endl;
    return 0;
}