Advertisement
erek1e

IOI '11 P2 - Race (Standard I/O)

Jul 5th, 2023
561
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 4.19 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <functional>
  5.  
  6. using namespace std;
  7.  
  8. const int INF = 1e9;
  9.  
  10. int n, k;
  11. vector<vector<pair<int, int>>> g;
  12. vector<bool> blockedNode;
  13.  
  14. vector<vector<int>> subtree; // depth, node
  15. int findComponentCentroid(int node, int depth = 0) {
  16.     // first find subtree sizes with node as root
  17.     while ((int)subtree.size() <= depth) subtree.emplace_back(n);
  18.     function<int(int, int)> getSubtree = [&](int v, int parent = -1) {
  19.         subtree[depth][v] = 1;
  20.         for (auto [u, w] : g[v]) {
  21.             if (!blockedNode[u] && u != parent) subtree[depth][v] += getSubtree(u, v);
  22.         }
  23.         return subtree[depth][v];
  24.     };
  25.     int m = getSubtree(node, -1);
  26.  
  27.     int centroid = node;
  28.     for (bool going = true; going; ) {
  29.         going = false;
  30.         for (auto [child, w] : g[centroid]) {
  31.             if (subtree[depth][child] < subtree[depth][centroid] && 2*subtree[depth][child] > m) {
  32.                 going = true;
  33.                 centroid = child;
  34.                 break;
  35.             }
  36.         }
  37.     }
  38.     return centroid;
  39. }
  40.  
  41. // Centroid Decomposition
  42. int getComponentMin(int node, int depth = 0) { // shortest path of weight k in component of node
  43.     vector<tuple<int, int, int>> paths; // weight, edges, component
  44.     function<void(int, int, int, int, int)> findPaths = [&](int v, int parent, int direction, int distance, int edges) {
  45.         paths.emplace_back(distance, edges, direction);
  46.         for (auto [u, w] : g[v]) {
  47.             if (!blockedNode[u] && u != parent) findPaths(u, v, direction, distance+w, edges+1);
  48.         }
  49.     };
  50.  
  51.     int centroid = findComponentCentroid(node, depth);
  52.     for (auto [child, w] : g[centroid]) {
  53.         if (!blockedNode[child]) findPaths(child, centroid, child, w, 1);
  54.     };
  55.  
  56.     // Consider all paths containing centroid
  57.     sort(paths.begin(), paths.end());
  58.     vector<pair<pair<int, int>, pair<int, int>>> weights; // weight, best direction, min edges, second best min edges
  59.     for (size_t i = 0; i < paths.size(); ++i) {
  60.         if (i && get<0>(paths[i-1]) == get<0>(paths[i])) continue; // already considered
  61.         pair<int, int> mn{INF, INF}; // min number of edges for this weight: edges, direction
  62.         for (size_t j = i; j < paths.size() && get<0>(paths[j]) == get<0>(paths[i]); ++j) {
  63.             mn = min(mn, {get<1>(paths[j]), get<2>(paths[j])});
  64.         }
  65.         int mn2 = INF; // min number of edges but in a different direction: edges
  66.         for (size_t j = i; j < paths.size() && get<0>(paths[j]) == get<0>(paths[i]); ++j) {
  67.             if (get<2>(paths[j]) != mn.second) mn2 = min(mn2, get<1>(paths[j]));
  68.         }
  69.         weights.push_back({{get<0>(paths[i]), mn.second}, {mn.first, mn2}});
  70.     }
  71.  
  72.     int minEdges = INF;
  73.     for (int i = 0, j = (int)weights.size()-1; i < (int)weights.size() && j >= 0; ++i) {
  74.         while (j >= 0 && weights[i].first.first + weights[j].first.first > k) --j;
  75.         if (j >= 0 && weights[i].first.first + weights[j].first.first == k) {
  76.             int edges;
  77.             if (weights[i].first.second == weights[j].first.second) {
  78.                 edges = min(weights[i].second.first + weights[j].second.second, weights[i].second.second + weights[j].second.first);
  79.             } else edges = weights[i].second.first + weights[j].second.first;
  80.             minEdges = min(minEdges, edges);
  81.         }
  82.     }
  83.     for (size_t i = 0; i < weights.size(); ++i) {
  84.         if (weights[i].first.first == k) minEdges = min(minEdges, weights[i].second.first);
  85.     }
  86.  
  87.     // Recur on neighbor's components
  88.     blockedNode[centroid] = true;
  89.     for (auto [child, w] : g[centroid]) {
  90.         if (!blockedNode[child]) minEdges = min(minEdges, getComponentMin(child, depth+1));
  91.     }
  92.    
  93.     // Return minimum
  94.     return minEdges;
  95. }
  96.  
  97. int main() {
  98.     ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  99.     cin >> n >> k;
  100.     g.resize(n);
  101.     blockedNode.resize(n);
  102.     for (int i = 1; i < n; ++i) {
  103.         int u, v, w; cin >> u >> v >> w;
  104.         g[u].emplace_back(v, w);
  105.         g[v].emplace_back(u, w);
  106.     }
  107.     int minEdges = getComponentMin(0);
  108.     cout << (minEdges == INF ? -1 : minEdges) << endl;
  109.     return 0;
  110. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement