#include using namespace std; using pii = pair; struct State { int N; vector A; vector alive; vector> G; State( int N_, const vector& edges, const vector& A_ ) : N(N_), A(A_), alive(N_, true), G(N_) { for (auto [u,v] : edges) { G[u].insert(v); G[v].insert(u); } } bool connected(int u, int v) const { return alive[u] && alive[v] && G[u].count(v); } // u, v を縮約し、生き残った頂点番号を返す int contract_edge(int u, int v) { assert(connected(u,v)); assert((A[u] & 1) == (A[v] & 1)); int nv = (A[u] + A[v]) / 2; G[u].erase(v); G[v].erase(u); // small-to-large if (G[u].size() < G[v].size()) { swap(u,v); } vector tmp( G[v].begin(), G[v].end() ); for (int x : tmp) { G[x].erase(v); G[x].insert(u); G[u].insert(x); } G[v].clear(); alive[v] = false; A[u] = nv; return u; } bool is02(int u, int v) const { return (A[u] == 0 && A[v] == 2) || (A[u] == 2 && A[v] == 0); } bool same(int u, int v) const { return A[u] == A[v]; } vector get_edges() const { vector es; for (int u=0; u cand; for (auto [u,v] : s.get_edges()) { if (s.is02(u,v)) { cand.push_back({u,v}); } } shuffle( cand.begin(), cand.end(), rng ); int cnt = 0; for (auto [u,v] : cand) { if (!s.connected(u,v)) continue; if (!s.is02(u,v)) continue; s.contract_edge(u,v); cnt++; } return cnt; } // ------------------------------------------------------------ // 同値フェーズ // // 0-0, 1-1, 2-2 をランダム順に縮約。 // 同値縮約によって新しい同値辺が生える可能性があるため、 // 何も縮約できなくなるまで繰り返す。 // ------------------------------------------------------------ int phase_same(State& s) { int total = 0; while (true) { vector cand; for (auto [u,v] : s.get_edges()) { if (s.same(u,v)) { cand.push_back({u,v}); } } if (cand.empty()) break; shuffle( cand.begin(), cand.end(), rng ); int cnt = 0; for (auto [u,v] : cand) { if (!s.connected(u,v)) continue; if (!s.same(u,v)) continue; s.contract_edge(u,v); cnt++; total++; } if (cnt == 0) break; } return total; } // ------------------------------------------------------------ // 1試行 // // 0-2 // ↓ // 同値 // ↓ // 0-2 // ↓ // 同値 // ... // // と収束まで繰り返す。 // ------------------------------------------------------------ int trial( int N, const vector& edges, const vector& A ) { State s(N,edges,A); int ans = 0; while (true) { int add = 0; add += phase02(s); add += phase_same(s); ans += add; if (add == 0) { break; } } return ans; } void solve() { int N; cin >> N; vector edges; for (int i = 0; i < N - 1; i++) { int u, v; cin >> u >> v; --u; --v; edges.push_back({u, v}); } vector A(N); for (int& x : A) { cin >> x; } int ans = 0; auto start = chrono::steady_clock::now(); // 2秒制限なので少し余裕を持たせる constexpr double TIME_LIMIT = 1.85; int trials = 0; while (true) { auto now = chrono::steady_clock::now(); double elapsed = chrono::duration(now - start).count(); if (elapsed >= TIME_LIMIT) { break; } ans = max( ans, trial(N, edges, A) ); trials++; // 理論上限まで行ったら即終了 if (ans == N - 1) { break; } } // cerr << "trials = " << trials << '\n'; cout << ans << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); solve(); }