Submission #1143686

#TimeUsernameProblemLanguageResultExecution timeMemory
1143686OtalpUnique Cities (JOI19_ho_t5)C++20
4 / 100
501 ms339968 KiB
#include <bits/stdc++.h> using namespace std; // -------------------- Data Structure ------------------------- // For a given distance d (from some “root”) we store: // cnt = number of nodes at that distance, // cand = if cnt==1 then the candidate speciality from that unique node; otherwise, cand = -1. struct PairEntry { int cnt; int cand; }; // Combine two PairEntry values from the same distance slot. inline PairEntry combinePair(const PairEntry &a, const PairEntry &b) { PairEntry res; res.cnt = a.cnt + b.cnt; if(res.cnt == 1) { // Exactly one nonzero contribution. res.cand = (a.cnt == 1 ? a.cand : b.cand); } else { res.cand = -1; } return res; } // Given two distributions A and B (vectors indexed by distance), // return their element–wise combination. // (If one vector is shorter, treat the missing slots as {0, -1}.) vector<PairEntry> combineDist(const vector<PairEntry>& A, const vector<PairEntry>& B) { int n = max(A.size(), B.size()); vector<PairEntry> res(n, {0, -1}); for (int i = 0; i < n; i++){ PairEntry a = (i < A.size() ? A[i] : PairEntry{0, -1}); PairEntry b = (i < B.size() ? B[i] : PairEntry{0, -1}); res[i] = combinePair(a, b); } return res; } // When “merging” the distribution from a child into the parent’s distribution, // we must shift the child’s distribution by 1 (since the distance increases by 1). void mergeShift(vector<PairEntry>& base, const vector<PairEntry>& child) { int shift = 1; int newSize = max((int)base.size(), (int)child.size() + shift); if(base.size() < newSize) base.resize(newSize, {0, -1}); for (int i = 0; i < (int)child.size(); i++){ int pos = i + shift; base[pos] = combinePair(base[pos], child[i]); } } // --------------------- Global Variables --------------------- int N, M; vector<int> C; // Speciality for each city (0-indexed) vector<vector<int>> adj; // Tree: adj[u] holds neighbors of u. // dp[x] will store the distribution for the subtree rooted at x. // In dp[x], index d (d>=0) represents: in the subtree of x, there are dp[x][d].cnt nodes at distance d (from x) // and if dp[x][d].cnt==1, then dp[x][d].cand is that unique node’s speciality. vector<vector<PairEntry>> dp; // ans[x] will be the answer for city x. vector<int> ans; // --------------------- DFS 1: Down–DFS ------------------------- // Compute dp[x] for the subtree rooted at x. // Initially, dp[x][0] = {1, C[x]} (city x itself). // Then for every child, we shift its dp and merge it into dp[x]. void dfs_down(int x, int parent) { dp[x].clear(); dp[x].push_back({1, C[x]}); // distance 0: city x. for (int v : adj[x]) { if(v == parent) continue; dfs_down(v, x); mergeShift(dp[x], dp[v]); } } // --------------------- DFS 2: Up–DFS (Re–rooting) ------------------------- // For node x, given an "up" distribution (from nodes not in x’s subtree), // we compute the full distribution F[x] = combineDist(up, dp[x]). // Then we count the number of distinct specialities coming from unique layers (d>=1). // Afterwards, using a prefix–suffix technique we compute an up–distribution for each child. void dfs_up(int x, int parent, const vector<PairEntry>& up) { // Full distribution for x = parent's up + dp[x]. vector<PairEntry> full = combineDist(up, dp[x]); // For every distance d>=1, if full[d].cnt==1 then that unique node (at distance d) provides its speciality. // Count distinct specialities (if the same speciality appears in two layers, count it once). unordered_set<int> uniqSpecs; for (int d = 1; d < (int)full.size(); d++){ if(full[d].cnt == 1) uniqSpecs.insert(full[d].cand); } ans[x] = uniqSpecs.size(); // Prepare the list of children (neighbors except parent) vector<int> children; for (int v : adj[x]) if(v != parent) children.push_back(v); int k = children.size(); // Build prefix and suffix arrays for the contributions from x’s children. // For each child v, we consider its branch distribution: dp[v] shifted by 1. vector< vector<PairEntry> > pref(k+1), suf(k+1); pref[0].clear(); for (int i = 0; i < k; i++){ int v = children[i]; vector<PairEntry> branch; if(dp[v].empty()){ branch.clear(); } else { branch.resize(dp[v].size() + 1, {0, -1}); for (int j = 0; j < (int)dp[v].size(); j++){ branch[j+1] = dp[v][j]; } } pref[i+1] = combineDist(pref[i], branch); } suf[k].clear(); for (int i = k-1; i >= 0; i--){ int v = children[i]; vector<PairEntry> branch; if(dp[v].empty()){ branch.clear(); } else { branch.resize(dp[v].size() + 1, {0, -1}); for (int j = 0; j < (int)dp[v].size(); j++){ branch[j+1] = dp[v][j]; } } suf[i] = combineDist(branch, suf[i+1]); } // For each child, compute its up distribution and DFS. for (int i = 0; i < k; i++){ int v = children[i]; // x’s own contribution (as a distribution: one node at distance 0). vector<PairEntry> baseVec; baseVec.push_back({1, C[x]}); // Siblings’ contribution: merge contributions from children before and after v. vector<PairEntry> siblings = combineDist(pref[i], suf[i+1]); // R = (x itself) + (siblings). vector<PairEntry> R = combineDist(baseVec, siblings); // Combine with parent's up–distribution. vector<PairEntry> newUp = combineDist(up, R); // Now shift newUp by 1 so that distances are measured from child v. vector<PairEntry> shiftedNewUp; if(newUp.empty()){ shiftedNewUp.clear(); } else { shiftedNewUp.resize(newUp.size() + 1, {0, -1}); for (int j = 0; j < (int)newUp.size(); j++){ shiftedNewUp[j+1] = newUp[j]; } } dfs_up(v, x, shiftedNewUp); } } // ------------------------- Main ------------------------- int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> N >> M; adj.assign(N, vector<int>()); dp.assign(N, vector<PairEntry>()); ans.assign(N, 0); C.resize(N); // Read the N-1 roads. for (int i = 0; i < N-1; i++){ int u, v; cin >> u >> v; u--; v--; // convert to 0-indexed. adj[u].push_back(v); adj[v].push_back(u); } // Read the speciality for each city. for (int i = 0; i < N; i++){ cin >> C[i]; } // First DFS: compute the dp distribution for each subtree. dfs_down(0, -1); // Second DFS: re–rooting. // For the root, there is no parent's up–distribution. vector<PairEntry> up; up.clear(); dfs_up(0, -1, up); // Output the answer for each city. for (int i = 0; i < N; i++){ cout << ans[i] << "\n"; } return 0; }
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...