/// GPT 5.6 Sol #include using namespace std; using ll = long long; const ll NEG = -(1LL << 60); struct DSU { vector p, sz; DSU(int n): p(n), sz(n,1) { iota(p.begin(), p.end(), 0); } int find(int x) { if (p[x] == x) return x; return p[x] = find(p[x]); } void unite(int a, int b) { a = find(a); b = find(b); if (a == b) return; if (sz[a] < sz[b]) swap(a,b); p[b] = a; sz[a] += sz[b]; } }; struct Edge { int to; int here; // この成分側の元頂点 int there; // 相手成分側の元頂点 bool trigger; // 0-2 辺か }; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; cin >> N; vector> es(N-1); for (auto &[u,v] : es) { cin >> u >> v; --u; --v; } vector A(N); for (int &x : A) cin >> x; DSU dsu(N); for (auto [u,v] : es) { if (A[u] == A[v]) { dsu.unite(u,v); } } vector id(N,-1); unordered_map mp; vector label; for (int i=0;i> G(K); for (auto [u,v] : es) { int a = id[u]; int b = id[v]; if (a == b) continue; bool trigger = (A[u] == 0 && A[v] == 2) || (A[u] == 2 && A[v] == 0); G[a].push_back({b,u,v,trigger}); G[b].push_back({a,v,u,trigger}); } vector par(K,-1); vector parAttach(K,-1); vector parTrigger(K,false); vector order = {0}; par[0] = -2; for (int i=0;i<(int)order.size();i++) { int v = order[i]; for (auto e : G[v]) { if (par[e.to] != -1) continue; par[e.to] = v; parAttach[e.to] = e.there; parTrigger[e.to] = e.trigger; order.push_back(e.to); } } // dp[v][parentTrigger][active] vector,2>> dp(K); for (int v=0;v=0;oi--) { int v = order[oi]; vector children; for (auto e : G[v]) { if (par[e.to] == v) children.push_back(e); } // label 1 は常に active if (label[v] == 1) { ll val = 0; for (auto e : children) { int c = e.to; val += max( dp[c][0][0], dp[c][0][1] + 1 ); } dp[v][0][1] = val; continue; } // ------------------------- // inactive // ------------------------- { ll val = 0; for (auto e : children) { int c = e.to; val += max(dp[c][0][0], dp[c][0][1]); } dp[v][0][0] = val; } // active のとき、 // まず全子辺を「発火辺にしない」とした baseline ll base = 0; // 元頂点 -> その頂点から発火させる場合の最大 delta unordered_map bestDelta; for (auto e : children) { int c = e.to; ll U = max( dp[c][0][0], dp[c][0][1] + 1 ); base += U; if (e.trigger) { ll S = dp[c][1][1] + 1; ll delta = S - U; auto it = bestDelta.find(e.here); if (it == bestDelta.end()) bestDelta[e.here] = delta; else it->second = max(it->second, delta); } } // ------------------------- // 親発火なしで active // -> 子発火を少なくとも1本使う // ------------------------- { ll g0 = 0; ll g1 = NEG; for (auto [x,d] : bestDelta) { ll ng0 = g0; ll ng1 = max( g1 + max(0LL,d), g0 + d ); g0 = ng0; g1 = ng1; } if (g1 > NEG/2) dp[v][0][1] = base + g1; } // ------------------------- // 親発火あり // ------------------------- if (v != 0 && parTrigger[v]) { int blocked = parAttach[v]; ll gain = 0; for (auto [x,d] : bestDelta) { if (x == blocked) continue; gain += max(0LL,d); } dp[v][1][1] = base + gain; } } ll add = max(dp[0][0][0], dp[0][0][1]); cout << (N-K) + add << '\n'; }