import sys from array import array # ------------------------------------------------------------ # RMQ-LCA (Euler tour + Sparse Table for depth-minimum) # - LCA: O(1) # - dist: O(1) # Segment Tree over Euler-in order for active (black) nodes: # - update/query: O(log N) # Overall: O((N+Q) log N) time, O(N log N) memory (Sparse Table) # ------------------------------------------------------------ def solve(): input = sys.stdin.buffer.readline N = int(input()) g = [[] for _ in range(N + 1)] for _ in range(N - 1): a, b = map(int, input().split()) g[a].append(b) g[b].append(a) color = [0] + list(map(int, input().split())) # ----------------------------- # Rooted tree at 1: depth[], tin/tout, euler_in (for subtree interval) # + Euler tour for RMQ-LCA: euler2 (len ~ 2N-1), dep2 # ----------------------------- depth = [0] * (N + 1) parent = [0] * (N + 1) tin = [0] * (N + 1) tout = [0] * (N + 1) euler_in = [0] * N # For RMQ-LCA first = [-1] * (N + 1) euler2 = array('I') # vertex ids dep2 = array('I') # depths along euler2 timer = 0 it = [0] * (N + 1) stack = [1] parent[1] = 0 depth[1] = 0 # Iterative DFS generating: # - tin/tout and euler_in (entry order) # - full Euler tour for RMQ-LCA (append on entry and after returning from child) while stack: v = stack[-1] if it[v] == 0: tin[v] = timer euler_in[timer] = v timer += 1 if first[v] == -1: first[v] = len(euler2) euler2.append(v) dep2.append(depth[v]) if it[v] < len(g[v]): to = g[v][it[v]] it[v] += 1 if to == parent[v]: continue parent[to] = v depth[to] = depth[v] + 1 stack.append(to) else: tout[v] = timer - 1 stack.pop() if stack: p = stack[-1] # append parent again when returning euler2.append(p) dep2.append(depth[p]) M = len(euler2) # ~ 2N-1 # ----------------------------- # Sparse Table for RMQ over dep2 (store indices into euler2) # ----------------------------- logs = array('I', [0]) * (M + 1) for i in range(2, M + 1): logs[i] = logs[i >> 1] + 1 K = logs[M] + 1 st = [None] * K # level 0: indices 0..M-1 st0 = array('I', range(M)) st[0] = st0 j = 1 length = M while (1 << j) <= M: prev = st[j - 1] span = 1 << (j - 1) new_len = M - (1 << j) + 1 cur = array('I', [0]) * new_len # cur[i] = argmin(dep2[prev[i]], dep2[prev[i+span]]) for i in range(new_len): i1 = prev[i] i2 = prev[i + span] cur[i] = i1 if dep2[i1] <= dep2[i2] else i2 st[j] = cur j += 1 def lca(a: int, b: int) -> int: ia = first[a] ib = first[b] if ia > ib: ia, ib = ib, ia k = logs[ib - ia + 1] i1 = st[k][ia] i2 = st[k][ib - (1 << k) + 1] return euler2[i1] if dep2[i1] <= dep2[i2] else euler2[i2] def dist(a: int, b: int) -> int: c = lca(a, b) return depth[a] + depth[b] - 2 * depth[c] def is_ancestor(a: int, b: int) -> bool: return tin[a] <= tin[b] and tout[b] <= tout[a] # jump_up via parent pointers in O(height) is too slow; use binary lifting for this part only # (needed to find child z on path y->x when y is ancestor of x) LOG = (N).bit_length() up = [[0] * (N + 1) for _ in range(LOG)] up0 = up[0] for v in range(1, N + 1): up0[v] = parent[v] for k in range(1, LOG): cur = up[k] prev = up[k - 1] for v in range(1, N + 1): mid = prev[v] cur[v] = prev[mid] if mid else 0 def jump_up(v: int, k: int) -> int: bit = 0 while k: if k & 1: v = up[bit][v] k >>= 1 bit += 1 return v # ----------------------------- # Segment Tree over euler_in positions [0..N) # Agg = (cnt, first_vertex, last_vertex, sum_dist_consecutive) # ----------------------------- def merge(L, R): if L[0] == 0: return R if R[0] == 0: return L return (L[0] + R[0], L[1], R[2], L[3] + R[3] + dist(L[2], R[1])) def steiner_vertices(agg) -> int: cnt, fv, lv, s = agg if cnt == 0: return 0 if cnt == 1: return 1 cycle = s + dist(lv, fv) edges = cycle // 2 return edges + 1 size = 1 while size < N: size <<= 1 seg = [(0, -1, -1, 0)] * (2 * size) # build leaves for i in range(N): v = euler_in[i] if color[v] == 1: seg[size + i] = (1, v, v, 0) for i in range(size - 1, 0, -1): seg[i] = merge(seg[i << 1], seg[i << 1 | 1]) def update(pos: int, v_or_minus1: int): i = size + pos if v_or_minus1 == -1: seg[i] = (0, -1, -1, 0) else: v = v_or_minus1 seg[i] = (1, v, v, 0) i >>= 1 while i: seg[i] = merge(seg[i << 1], seg[i << 1 | 1]) i >>= 1 def query(l: int, r: int): # [l, r) left = (0, -1, -1, 0) right = (0, -1, -1, 0) l += size r += size while l < r: if l & 1: left = merge(left, seg[l]) l += 1 if r & 1: r -= 1 right = merge(seg[r], right) l >>= 1 r >>= 1 return merge(left, right) def query_subtree(u: int) -> int: l = tin[u] r = tout[u] + 1 return steiner_vertices(query(l, r)) def query_complement_subtree(u: int) -> int: l = tin[u] r = tout[u] + 1 left = query(0, l) right = query(r, N) return steiner_vertices(merge(left, right)) # ----------------------------- # Process Queries # ----------------------------- Q = int(input()) out = [] for _ in range(Q): parts = input().split() t = int(parts[0]) if t == 1: v = int(parts[1]) color[v] ^= 1 if color[v] == 1: update(tin[v], v) else: update(tin[v], -1) else: x = int(parts[1]) y = int(parts[2]) if x == y: out.append(str(steiner_vertices(query(0, N)))) continue if is_ancestor(y, x): # z: child of y on path to x z = jump_up(x, depth[x] - depth[y] - 1) out.append(str(query_complement_subtree(z))) else: out.append(str(query_subtree(y))) sys.stdout.write("\n".join(out)) if __name__ == "__main__": solve()