Submission #1163779

#TimeUsernameProblemLanguageResultExecution timeMemory
1163779ChottuFRailway (BOI17_railway)C++20
100 / 100
79 ms28360 KiB
#include <bits/stdc++.h> using namespace std; const int MAXN = 100005; const int MAXH = 18; // since n <= 1e5, log2(n) < 18 int n, m, k; vector<vector<int>> adj; int depth[MAXN], parentArr[MAXN]; int up[MAXH][MAXN]; int tin[MAXN], tout[MAXN], timer = 0; // DFS to compute tin/tout, depth and immediate parent. void dfs(int u, int p, int d) { depth[u] = d; parentArr[u] = p; tin[u] = ++timer; up[0][u] = p; for (int v : adj[u]) { if (v == p) continue; dfs(v, u, d+1); } tout[u] = timer; } // Standard binary lifting LCA. int lca(int a, int b) { if(depth[a] < depth[b]) swap(a, b); int d = depth[a] - depth[b]; for (int i = 0; i < MAXH; i++){ if(d & (1 << i)) a = up[i][a]; } 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 parentArr[a]; } // Global difference array. // For each query we “update” the virtual tree edges by (conceptually) // adding a query on the entire path from the virtual parent to the child. // For a path update from u to v (with u an ancestor of v), the standard method is: // freq[u] += 1; freq[v] += 1; freq[u] -= 2 (since lca(u,v)==u) // which is equivalent to: freq[u] -= 1; freq[v] += 1. int freq[MAXN]; // After processing all queries we do a DFS (postorder) to accumulate the freq values: // for every node v (other than the root), the final freq[v] will equal the number of queries that used // the edge connecting v to its parent. void dfsAccumulate(int u, int p) { for (int v : adj[u]) { if(v == p) continue; dfsAccumulate(v, u); freq[u] += freq[v]; } } // Map each edge (stored as an ordered pair) to its track ID. map<pair<int,int>, int> edgeId; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m >> k; // Resize and initialize the tree. adj.resize(n+1); for (int i = 1; i <= n-1; i++){ int u, v; cin >> u >> v; adj[u].push_back(v); adj[v].push_back(u); int a = min(u, v), b = max(u, v); edgeId[{a, b}] = i; } // Precompute DFS order and binary lifting table. dfs(1, 0, 0); for (int i = 1; i < MAXH; i++){ for (int u = 1; u <= n; u++){ int par = up[i-1][u]; up[i][u] = (par == 0 ? 0 : up[i-1][par]); } } // Process each deputy minister's query. // For each query we build the Steiner tree (i.e. the minimal subtree that connects the chosen nodes). // We do this by: // 1. Sorting the chosen nodes by tin. // 2. Adding the LCA for every consecutive pair. // 3. Removing duplicates and sorting again. // 4. Building the virtual tree using a stack. // For every virtual tree edge (u,v) with u as the parent (which equals lca(u,v)), // we update: freq[u] -= 1; freq[v] += 1; 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(nodes.begin(), nodes.end(), [](int a, int b){ return tin[a] < tin[b]; }); vector<int> virt = nodes; // Add LCAs of consecutive nodes. for (int i = 1; i < s; i++){ int l = lca(nodes[i-1], nodes[i]); virt.push_back(l); } // Remove duplicates. sort(virt.begin(), virt.end(), [](int a, int b){ return tin[a] < tin[b]; }); virt.erase(unique(virt.begin(), virt.end()), virt.end()); // Build the virtual tree. vector<int> st; for (int u : virt) { while (!st.empty() && tout[st.back()] < tin[u]) st.pop_back(); if (!st.empty()){ int par = st.back(); // For a virtual edge from par to u (with par == lca(par, u)), // perform the update corresponding to a path update: // (freq[par] += 1, freq[u] += 1, freq[par] -= 2) <=> (freq[par] -= 1, freq[u] += 1). freq[par] -= 1; freq[u] += 1; } st.push_back(u); } } // Propagate the difference values: do a postorder DFS on the original tree. dfsAccumulate(1, 0); // For every edge (v, parent[v]) (v != 1) the final freq[v] is the number of queries that required that edge. vector<int> answer; for (int v = 2; v <= n; v++){ if (freq[v] >= k) { int u = parentArr[v]; int a = min(u, v), b = max(u, v); answer.push_back(edgeId[{a, b}]); } } sort(answer.begin(), answer.end()); cout << answer.size() << "\n"; for (int id : answer) cout << id << " "; 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...