hihocoder 1160 攻城略地

来源:互联网 发布:网络教育属于全日制吗 编辑:程序博客网 时间:2024/05/01 11:40

先并查集处理出每个集合,和每个集合最小的点的下标

然后把每个点权值从大到排序,砍k条边其实相当于加m - k条边,每次加一条边可以减少一个点的权值(除了每个集合的最小点),这样从大到小把能删的尽量贪心删掉即可

代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <vector>using namespace std;typedef long long ll;const int N = 1000005;const int INF = 0x3f3f3f3f;int t, n, m, k, w[N], parent[N], Min[N], id[N];int find(int x) {    if (x == parent[x]) return x;    return parent[x] = find(parent[x]);}bool cmp(int a, int b) {    return w[a] < w[b];}int main() {    int cas = 0;    scanf("%d", &t);    while (t--) {        ll ans = 0;        scanf("%d%d%d", &n, &m, &k);        for (int i = 1; i <= n; i++) {            Min[i] = INF;            parent[i] = i;            Min[i] = i;            scanf("%d", &w[i]);            id[i] = i;            ans += w[i];        }        int u, v;        for (int i = 0; i < m; i++) {            scanf("%d%d", &u, &v);            int pu = find(u);            int pv = find(v);            if (pu != pv) {                if (w[Min[pu]] < w[Min[pv]])                    Min[pv] = Min[pu];                parent[pu] = pv;            }        }        k = m - k;        sort(id + 1, id + n + 1, cmp);        for (int i = n; i >= 1; i--) if (k && Min[find(id[i])] != id[i]) ans -= w[id[i]], k--;        printf("Case #%d: %lld\n", ++cas, ans);    }    return 0;}


0 0
原创粉丝点击