Submission #1084603

#TimeUsernameProblemLanguageResultExecution timeMemory
1084603avighnaFirefighting (NOI20_firefighting)C++17
62 / 100
3064 ms64704 KiB
#include <bits/stdc++.h>

typedef long long ll;

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

  ll n, k;
  std::cin >> n >> k;
  std::vector<std::vector<std::pair<ll, ll>>> adj(n + 1);
  ll min_w = 1e15;
  for (ll i = 0, u, v, w; i < n - 1; ++i) {
    std::cin >> u >> v >> w;
    adj[u].push_back({v, w});
    adj[v].push_back({u, w});
    min_w = std::min(min_w, w);
  }

  if (k < min_w) {
    std::cout << n << '\n';
    for (ll i = 1; i <= n; ++i) {
      std::cout << i << ' ';
    }
    std::cout << '\n';
    return 0;
  }

  if (n <= 17) {
    std::pair<ll, ll> ans = {1e15, -1};
    for (ll mask = 1; mask < (1 << n); ++mask) {
      std::priority_queue<std::pair<ll, ll>> pq;
      std::vector<bool> vis(n + 1);
      std::vector<ll> dist(n + 1, 1e15);
      dist[0] = 0;
      for (ll i = 0; i < n; ++i) {
        if (mask & (1 << i)) {
          dist[i + 1] = 0;
          pq.push({0, i + 1});
        }
      }
      while (!pq.empty()) {
        auto [d, node] = pq.top();
        pq.pop();
        if (vis[node]) {
          continue;
        }
        vis[node] = true;
        d *= -1;
        for (auto &[ch, w] : adj[node]) {
          if (d + w < dist[ch]) {
            dist[ch] = d + w;
            pq.push({-dist[ch], ch});
          }
        }
      }
      if (*std::max_element(dist.begin(), dist.end()) <= k) {
        ans = std::min(ans, {__builtin_popcount(mask), mask});
      }
    }
    std::cout << ans.first << '\n';
    for (ll i = 0; i < n; ++i) {
      if (ans.second & (1 << i)) {
        std::cout << i + 1 << ' ';
      }
    }
    std::cout << '\n';
    return 0;
  }

  if (2 * min_w > k) {
    // dp[node][0] => you need to cover parent
    // dp[node][1] => parent covers you
    // dp[node][2] => you only need to cover your subtree
    std::vector<std::vector<ll>> dp(n + 1, std::vector<ll>(3, 1e15));
    std::vector<bool> is_leaf(n + 1, true);
    std::function<void(ll, ll, ll)> dfs;
    dfs = [&](ll node, ll par, ll wt) {
      ll sum = 0;
      for (auto &[ch, w] : adj[node]) {
        if (ch == par) {
          continue;
        }
        is_leaf[node] = false;
        dfs(ch, node, w);
        sum += dp[ch][2];
      }
      if (is_leaf[node]) {
        dp[node][0] = wt <= k ? 1 : 1e15;
        dp[node][1] = wt <= k ? 0 : 1e15;
        dp[node][2] = 1;
      } else {
        dp[node][0] = 1;
        dp[node][1] = 0;
        for (auto &[ch, w] : adj[node]) {
          if (ch == par) {
            continue;
          }
          if (w <= k) {
            dp[node][2] = std::min(dp[node][2], sum - dp[ch][2] + dp[ch][0]);
            dp[node][0] += dp[ch][1];
          } else {
            dp[node][0] += dp[ch][2];
          }
          dp[node][1] += dp[ch][2];
        }
        dp[node][1] = std::min(dp[node][1], dp[node][0]);
        dp[node][2] = std::min(dp[node][2], dp[node][0]);
      }
    };
    dfs(1, 0, 0);

    std::vector<ll> ans;
    std::function<void(ll, ll, ll)> build_ans;
    build_ans = [&](ll node, ll par, ll j) {
      if (is_leaf[node]) {
        if (j == 0 or j == 2) {
          ans.push_back(node);
        }
        return;
      }
      if (j == 0) {
        ans.push_back(node);
        for (auto &[ch, w] : adj[node]) {
          if (ch == par) {
            continue;
          }
          if (w <= k) {
            build_ans(ch, node, 1);
          } else {
            build_ans(ch, node, 2);
          }
        }
      } else if (j == 1) {
        if (dp[node][1] == dp[node][0]) {
          build_ans(node, par, 0);
          return;
        }
        for (auto &[ch, w] : adj[node]) {
          if (ch == par) {
            continue;
          }
          build_ans(ch, node, 2);
        }
      } else {
        if (dp[node][2] == dp[node][0]) {
          build_ans(node, par, 0);
          return;
        }
        ll sum = 0;
        for (auto &[ch, w] : adj[node]) {
          if (ch == par) {
            continue;
          }
          sum += dp[ch][2];
        }
        bool found = false;
        for (auto &[ch, w] : adj[node]) {
          if (ch == par) {
            continue;
          }
          if (!found and dp[node][2] == sum - dp[ch][2] + dp[ch][0]) {
            found = true;
            build_ans(ch, node, 0);
          } else {
            build_ans(ch, node, 2);
          }
        }
      }
    };
    build_ans(1, 0, 2);
    std::cout << dp[1][2] << '\n';
    for (auto &i : ans) {
      std::cout << i << ' ';
    }
    std::cout << '\n';
    return 0;
  }

  std::set<ll> active;
  for (ll i = 1; i <= n; ++i) {
    active.insert(i);
  }
  std::function<void(ll, ll, ll)> dfs;
  std::vector<std::pair<ll, ll>> up(n + 1);
  std::vector<ll> depths(n + 1);
  dfs = [&](ll node, ll par, ll depth) {
    depths[node] = depth;
    for (auto &[i, wt] : adj[node]) {
      if (i == par or !active.count(i)) {
        continue;
      }
      up[i] = {node, wt};
      dfs(i, node, depth + wt);
    }
  };
  dfs(1, 0, 0);
  std::priority_queue<std::pair<ll, ll>> pq;
  for (ll i = 1; i <= n; ++i) {
    pq.push({depths[i], i});
  }

  std::vector<ll> ans;
  while (!pq.empty()) {
    ll deepest = pq.top().second;
    pq.pop();
    if (!active.count(deepest)) {
      continue;
    }
    ll dist = 0;
    while (deepest != 1 and dist + up[deepest].second <= k) {
      dist += up[deepest].second;
      deepest = up[deepest].first;
    }
    ans.push_back(deepest);
    std::function<void(ll, ll, ll)> dfs2;
    dfs2 = [&](ll node, ll par, ll depth) {
      if (depth > k) {
        return;
      }
      active.erase(node);
      for (auto &[i, wt] : adj[node]) {
        if (i == par) {
          continue;
        }
        dfs2(i, node, depth + wt);
      }
    };
    dfs2(deepest, 0, 0);
  }
  std::cout << ans.size() << '\n';
  for (auto &i : ans) {
    std::cout << i << ' ';
  }
  std::cout << '\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...