Loading

abc 267 e 题解

abc 267 e

题意

给定一个 \(N\) 个点 \(M\) 条边的简单无向图,第 \(i\) 条边连接 \(U_i, V_i\),点 \(i\) 的点权为 \(A_i\)

重复以下操作 \(N\) 次:

  • 选择一个未被移除的点 \(x\),移除 \(x\) 和与 \(x\) 相连的所有边。这次操作的代价为所有与 \(x\) 直接相连的点的点权之和。

请你求出 \(N\) 次操作代价的最大值的最小可能值。

思路

二分

我们可以发现,答案越小,越难达到,有单调性,可以想到 二分

那么,我们应该如何判断每个值是否可行呢?

设我们当前要判断 \(X\) 是否可行,那么,我们肯定是先选择产生代价 \(\le x\) 的点删除。

而每次删除点,都只会使得与它直接相连的点所产生的代价变小,所以,每次只需要判断那些与它直接相连的点所产生的代价是否 \(\le X\) 即可。

\(V\) 为所有点权之和。

每次 Check() 的时间复杂度为 \(O(N + M)\),二分的时间复杂度为 \(O(\log V)\),所以总时间复杂度为 \(O((N + M) \times \log V)\)

代码

#include <bits/stdc++.h>

using namespace std;
using ll = long long;

const int N = 2e5 + 10;

int n, m, a[N];
bool f[N];
vector<int> g[N];
ll s[N];

bool Check(ll x) {
  queue<int> que;
  int c = 0; 
  for (int i = 1; i <= n; i++) {
    s[i] = f[i] = 0;
    for (int j : g[i]) {
      s[i] += a[j];
    }
    if (s[i] <= x) {
      que.push(i), f[i] = 1;
    }
  }
  while (!que.empty()) {
    int u = que.front();
    que.pop(), c++;
    for (int v : g[u]) {
      s[v] -= a[u];
      if (s[v] <= x && !f[v]) {
        que.push(v), f[v] = 1;
      }
    }
  }
  return c == n;
}

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  while (m--) {
    int u, v;
    cin >> u >> v;
    g[u].push_back(v), g[v].push_back(u);
  }
  ll l = 0, r = 2e14;
  while (l < r) {
    ll mid = (l + r) >> 1;
    if (Check(mid)) {
      r = mid;
    } else {
      l = mid + 1;
    }
  }
  cout << l;
  return 0;
}

贪心

每次选择产生代价最小的点删除,用堆或者 set 维护。

时间复杂度为 \(O((N + M) \times \log (N + M))\)

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int n, m, a[N];
long long sum[N], ans;
bool f[N];
vector<int> g[N];

struct Node {
  long long s;
  int id;
  bool operator < (const Node &i) const {
    return s > i.s;
  }
};

priority_queue<Node> pq;

int main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  while (m--) {
    int u, v;
    cin >> u >> v;
    g[u].push_back(v), g[v].push_back(u);
  }
  for (int i = 1; i <= n; i++) {
    for (int j : g[i]) {
      sum[i] += a[j];
    }
    pq.push({sum[i], i});
  }
  while (!pq.empty()) {
    Node u = pq.top();
    pq.pop();
    if (!f[u.id]) {
      f[u.id] = 1, ans = max(ans, u.s);
      for (int v : g[u.id]) {
        sum[v] -= a[u.id], pq.push({sum[v], v});
      }
    }
  }
  cout << ans;
  return 0;
}
posted @ 2023-05-14 20:48  chengning0909  阅读(8)  评论(0编辑  收藏  举报