제출 #1184196

#제출 시각아이디문제언어결과실행 시간메모리
1184196avighnaDesignated Cities (JOI19_designated_cities)C++20
33 / 100
211 ms129396 KiB
#include <bits/stdc++.h>

template <typename T> class SparseTable {
public:
  int maxPow;
  std::vector<T> orig;
  std::vector<std::vector<std::pair<T, int>>> table_max;

  SparseTable(const std::vector<T> &x) : orig(x) {
    const int n = x.size();
    maxPow = std::floor(std::log2(n));
    table_max = std::vector(maxPow + 1, std::vector<std::pair<T, int>>(n));
    for (int i = 0; i < n; ++i) {
      table_max[0][i] = {x[i], i};
    }
    for (int power = 1; power <= maxPow; ++power) {
      for (int i = 0; i < n - (1 << (power - 1)); ++i) {
        table_max[power][i] =
            std::max(table_max[power - 1][i],
                     table_max[power - 1][i + (1 << (power - 1))]);
      }
    }
  }

  std::pair<T, int> query_max(int a, int b) {
    if (a == b) {
      return {orig[a], a};
    }
    int powToUse = std::ceil(std::log2(b - a + 1)) - 1;
    return std::max(table_max[powToUse][a],
                    table_max[powToUse][b - (1 << powToUse) + 1]);
  }
};

int main() {
  std::ios_base::sync_with_stdio(false);
  std::cin.tie(nullptr);

  int n;
  std::cin >> n;
  std::vector<std::vector<std::pair<int, std::pair<long long, long long>>>> adj(
      n + 1);
  long long tot = 0;
  for (int i = 0, a, b, c, d; i < n - 1; ++i) {
    std::cin >> a >> b >> c >> d;
    adj[a].push_back({b, {c, d}});
    adj[b].push_back({a, {d, c}});
    tot += c + d;
  }

  std::vector<long long> path_up(n + 1), path_down(n + 1), ans(n + 1),
      start(n + 1), end(n + 1);
  std::vector<int> par(n + 1);
  long long up = 0, timer = 0;
  auto dfs = [&](auto &&self, int u, int p) -> void {
    start[u] = timer++;
    for (auto &[i, pr] : adj[u]) {
      if (i == p) {
        continue;
      }
      par[i] = u;
      auto [c, d] = pr;
      up += d;
      path_up[i] = path_up[u] + d;
      path_down[i] = path_down[u] + c;
      self(self, i, u);
    }
    end[u] = timer - 1;
  };
  dfs(dfs, 1, 0);
  for (int i = 1; i <= n; ++i) {
    ans[1] = std::max(ans[1], up - path_up[i] + path_down[i]);
  }
  std::pair<int, int> start_nodes;
  auto dfs1 = [&](auto &&self, int u, int p,
                  long long dep) -> std::pair<long long, int> {
    std::pair<long long, int> max_down = {path_down[u], u};
    std::vector<std::pair<long long, int>> v;
    for (auto &[i, pr] : adj[u]) {
      if (i == p) {
        continue;
      }
      auto [c, d] = pr;
      v.push_back(self(self, i, u, dep + c));
      max_down = std::max(max_down, v.back());
    }
    long long _u_ = up + dep - path_up[u];
    if (_u_ + (max_down.first - path_down[u]) > ans[2]) {
      ans[2] = _u_ + (max_down.first - path_down[u]);
      start_nodes = {u, max_down.second};
    }
    std::sort(v.rbegin(), v.rend());
    if (v.size() > 1) {
      if (_u_ + (v[0].first - path_down[u]) + (v[1].first - path_down[u]) >
          ans[2]) {
        ans[2] =
            _u_ + (v[0].first - path_down[u]) + (v[1].first - path_down[u]);
        start_nodes = {v[0].second, v[1].second};
      }
    }
    return max_down;
  };
  dfs1(dfs1, 1, 0, 0);

  // root at one of the start nodes and expand: anyways you will end up with the
  // first node being picked as the other start node
  int &node = start_nodes.first;
  up = timer = 0;
  path_down.assign(n + 1, 0), path_up.assign(n + 1, 0);
  dfs(dfs, node, 0);
  std::vector<long long> orig(n + 1);
  std::vector<int> get_node(n + 1);
  for (int i = 1; i <= n; ++i) {
    orig[start[i]] = path_down[i];
    get_node[start[i]] = i;
  }
  SparseTable<long long> table(orig);
  int idx = 1;
  std::priority_queue<std::pair<long long, std::pair<int, int>>> pq;
  auto pr = table.query_max(start[node], end[node]);
  pq.push({pr.first, {node, pr.second}});
  while (!pq.empty()) {
    auto [d, pr] = pq.top();
    auto [beg, tar] = pr;
    tar = get_node[tar];
    pq.pop();
    idx++;
    if (idx != 2) {
      ans[idx] = ans[idx - 1] + d;
    }
    int prev = 0;
    while (true) {
      for (auto &[i, pr] : adj[tar]) {
        if (i == par[tar] or i == prev) {
          continue;
        }
        auto pr2 = table.query_max(start[i], end[i]);
        pq.push({pr2.first - path_down[tar], {i, pr2.second}});
      }
      if (tar == beg) {
        break;
      }
      prev = tar;
      tar = par[tar];
    }
  }

  int q;
  std::cin >> q;
  while (q--) {
    int x;
    std::cin >> x;
    std::cout << tot - ans[x] << '\n';
  }
}
#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...