加载中...

树上删除点

给定一张n个点 m条边的无向图,点有点权。需要进行n次操作,每次操作,选择一个点a,并移除该点以及与该点相连的所有边,其代价是与点a直接相连的所有点权和。问所有操作的代价的最大值的最小值是多少。

暴力 + 根堆

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
 
int main(void) {
    ios::sync_with_stdio(false); 
    cin.tie(0); cout.tie(0);
    int n, m;
    cin >> n >> m;
    vector<LL> a(n);
    for(auto &i : a)
        cin >> i;
    vector<vector<int>> edge(n, vector<int>());
    vector<LL> sum(n, 0);
    for(int i = 1; i <= m; ++ i){
        int x, y;
        cin >> x >> y;
        -- x;
        -- y;
        edge[x].push_back(y);
        edge[y].push_back(x);
        sum[x] += a[y];//sum表示删除这个点需要的价值
        sum[y] += a[x];
    }
    priority_queue<pair<LL, int>> qwq;
    for(int i = 0; i < n; ++ i){
        qwq.push({- sum[i], i});
    }
    LL ans = 0;
    int cnt = n;
    set<int> ff;
    while(cnt){//不再以根堆的点作为点
        auto [val, u] = qwq.top();
        val = -val;
        qwq.pop();
        if (val != sum[u])
            continue;
        ff.insert(u);//插入这个点 表示这个点已经被删除了
        ans = max(ans, val);
        cnt --;
        for(auto &v : edge[u]){
            if (ff.find(v) != ff.end())//删除过的点不再处理
                continue;
            sum[v] -= a[u];//连接他的点的价值都减少
            qwq.push({-sum[v], v});//存负值因为默认大根堆取出来在变符号 就变最小值
        }
    }
    cout << ans << '\n';
    return 0;
}
posted @ 2022-09-06 22:25  liang302  阅读(38)  评论(0编辑  收藏  举报