Submission #1163777

#TimeUsernameProblemLanguageResultExecution timeMemory
1163777ChottuFRailway (BOI17_railway)C++20
0 / 100
117 ms45316 KiB
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e5+5; const int MAXH = 22; vector<vector<int>> adj; int up[MAXH][MAXN], depth[MAXN]; int tin[MAXN], tout[MAXN], timer = 0; // DFS to compute depth, parent pointers, and tin/tout times. void dfs(int x, int p, int d) { depth[x] = d; up[0][x] = p; tin[x] = ++timer; for(auto u : adj[x]) { if(u == p) continue; dfs(u, x, d+1); } tout[x] = timer; } int jmp(int x, int k) { for (int i = 0; i < MAXH; i++) { if(k & (1 << i)) x = up[i][x]; } return x; } int lca(int a, int b) { if(depth[a] < depth[b]) swap(a, b); a = jmp(a, depth[a]-depth[b]); if(a == b) return a; for (int i = MAXH-1; i >= 0; i--) { if(up[i][a] != up[i][b]) { a = up[i][a]; b = up[i][b]; } } return up[0][a]; } // We'll use diff[node] to hold a mapping (query id -> count) // representing the “difference” contributions from each query. map<int,int> diff[MAXN]; // After merging, ans[x] will be the number of queries that contributed to the edge (x, parent[x]). int ans[MAXN]; // DFS to merge difference maps using small-to-large merging. void dfs2(int x, int p) { for(auto u : adj[x]) { if(u == p) continue; dfs2(u, x); if(diff[x].size() < diff[u].size()) swap(diff[x], diff[u]); for(auto &entry : diff[u]) { diff[x][entry.first] += entry.second; if(diff[x][entry.first] == 0) diff[x].erase(entry.first); } } ans[x] = diff[x].size(); } int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); int n, m, k; cin >> n >> m >> k; adj.resize(n+1); // Map a track (stored as an ordered pair) to its ID. map<pair<int,int>, int> mpp; for (int i = 0; i < n-1; i++){ int a, b; cin >> a >> b; adj[a].push_back(b); adj[b].push_back(a); if(a > b) swap(a, b); mpp[{a, b}] = i+1; } // Precompute DFS order and LCA binary lifting arrays. dfs(1, 0, 1); for(int j = 1; j < MAXH; j++){ for(int i = 1; i <= n; i++){ up[j][i] = up[j-1][up[j-1][i]]; } } // Process each deputy minister's query. for (int q = 0; q < m; q++){ int s; cin >> s; vector<int> nodes(s); for (int i = 0; i < s; i++){ cin >> nodes[i]; } // Sort chosen nodes by their tin value. sort(nodes.begin(), nodes.end(), [&](int a, int b){ return tin[a] < tin[b]; }); // Build the set of nodes for the Steiner tree: // start with the chosen nodes and add LCAs for consecutive ones. vector<int> steiner = nodes; for (int i = 1; i < s; i++){ steiner.push_back(lca(nodes[i-1], nodes[i])); } sort(steiner.begin(), steiner.end(), [&](int a, int b){ return tin[a] < tin[b]; }); steiner.erase(unique(steiner.begin(), steiner.end()), steiner.end()); // Build the virtual tree using a stack. vector<int> st; // We will collect virtual tree edges as (parent, child). vector<pair<int,int>> vtEdges; for (int x : steiner) { while (!st.empty() && tout[st.back()] < tin[x]) { st.pop_back(); } if (!st.empty()) { vtEdges.push_back({st.back(), x}); } st.push_back(x); } // For every edge in the virtual tree, add a +1 contribution for query q at the child. for(auto &edge : vtEdges){ int parent = edge.first, child = edge.second; diff[child][q] += 1; } } // Merge difference maps over the entire tree. dfs2(1, 0); // For every edge (represented by node i with parent up[0][i]), if the aggregated // contribution (number of queries that requested that edge) is at least k, include that track. vector<int> answerEdges; for (int i = 2; i <= n; i++){ if(ans[i] >= k){ int a = i, b = up[0][i]; if(a > b) swap(a, b); answerEdges.push_back(mpp[{a, b}]); } } sort(answerEdges.begin(), answerEdges.end()); cout << answerEdges.size() << "\n"; for (auto x : answerEdges) cout << x << " "; cout << "\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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...