Advertisement
erek1e

Storm in a Teacup (faster) - BIO 2024 Round 2

Apr 28th, 2024
723
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.67 KB | None | 0 0
  1. /**
  2.  * @file teacup.cpp
  3.  * @version 1.0
  4.  * @date 2024-03-30
  5.  *
  6.  * usage:
  7.  *      Read from / write to default input.txt and output.txt
  8.  *          teacup.exe
  9.  *      Read from / write to custom files:
  10.  *          teacup.exe in.txt out.txt
  11.  */
  12. // This is a constant-optimised solution - the problem had a very tight time limit. My other solution is cleaner and less complex, although it has a larger constant.
  13. #include <iostream>
  14. #include <vector>
  15. #include <algorithm>
  16. #include <queue>
  17. #include <numeric>
  18.  
  19. #include <cassert>
  20.  
  21. using namespace std;
  22.  
  23. void fileIO(int argc, char *argv[]);
  24.  
  25. const int MX = 1<<20;
  26. int parent[1+MX], components[1+MX];
  27. long long leftoverSum[1+MX];
  28.  
  29. int main(int argc, char *argv[]) {
  30.     fileIO(argc, argv); // remove for standard input/output
  31.     ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
  32.  
  33.     int h, f; cin >> h >> f;
  34.     vector<int> value(h);
  35.     for (int &x : value) cin >> x;
  36.  
  37.     vector<vector<int>> g(h);
  38.     for (int i = 0; i < h-1; ++i) {
  39.         int u, v; cin >> u >> v;
  40.         --u, --v;
  41.         g[u].push_back(v);
  42.         g[v].push_back(u);
  43.     }
  44.  
  45.     // precalculate order using bfs to topo sort, do not need queues
  46.     vector<int> order;
  47.     order.push_back(0);
  48.     parent[0] = h; // no parent
  49.     for (size_t nxt = 0; nxt < order.size(); ++nxt) {
  50.         int node = order[nxt];
  51.         for (int child : g[node]) {
  52.             if (child != parent[node]) {
  53.                 order.push_back(child);
  54.                 parent[child] = node;
  55.             }
  56.         }
  57.     }
  58.     assert((int)order.size() == h);
  59.  
  60.     // reindex nodes in this order
  61.     vector<vector<int>> g2(h);
  62.     vector<int> iAt(h);
  63.     for (int i = 0; i < h; ++i) iAt[order[i]] = i;
  64.     assert(iAt[0] == 0);
  65.     for (int i = 0; i < h; ++i) {
  66.         for (int j : g[i]) {
  67.             if (j == parent[i]) continue;
  68.             g2[iAt[i]].push_back(iAt[j]);
  69.             assert(iAt[i] < iAt[j]);
  70.         }
  71.     }
  72.     vector<int> value2(h);
  73.     for (int i = 0; i < h; ++i) value2[iAt[i]] = value[i];
  74.  
  75.     // Binary Search on the answer
  76.     long long sum = accumulate(value.begin(), value.end(), 0LL);
  77.     long long left = 0, right = sum/f + 1;
  78.     while (left+1 < right) {
  79.         long long minComponentSum = (left + right) / 2;
  80.         /* check if the graph can be split into f components,
  81.         each with sum >= minComponentSum */
  82.  
  83.         // dp on subtrees
  84.  
  85.         bool works = false;
  86.  
  87.         // not using node : order and child : g[node] since it is slower
  88.         for (int node = (int)order.size()-1; node >= 0; --node) {
  89.             components[node] = 0, leftoverSum[node] = value2[node];
  90.             for (size_t j = 0; j < g2[node].size(); ++j) {
  91.                 int child = g2[node][j];
  92.                 // can avoid making sure child is not parent node, since parent's values are 0
  93.                 components[node] += components[child];
  94.                 leftoverSum[node] += leftoverSum[child];
  95.             }
  96.             if (leftoverSum[node] >= minComponentSum) {
  97.                 leftoverSum[node] = 0;
  98.                 ++components[node];
  99.             }
  100.             // if (components[node] >= f) {
  101.             //     works = true;
  102.             //     break;
  103.             // }
  104.         }
  105.  
  106.         // if dfs from arbitrary root yields at least f components
  107.         if (works || components[0] >= f) left = minComponentSum;
  108.         else right = minComponentSum;
  109.     }
  110.     cout << left << '\n';
  111.     return 0;
  112. }
  113.  
  114. void fileIO(int argc, char *argv[]) {
  115.     const char * in = "input.txt", * out = "output.txt";
  116.     if (argc > 1) in = argv[1];
  117.     if (argc > 2) out = argv[2];
  118.     freopen(in, "r", stdin);
  119.     freopen(out, "w", stdout);
  120. }
  121.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement