码迷,mamicode.com
首页 > 其他好文 > 详细

Atcoder Nikki Qual E Bridge

时间:2019-09-01 22:11:51      阅读:156      评论:0      收藏:0      [点我收藏+]

标签:print   星球大战   维护   sort   tor   struct   启示   数组   include   

题意

给一张无向图,点带权,边也带权

要求在图中删去最少的边,使得对于每一条边,它所在连通块的点权之和大于其边权


解法

首先,看到题目里出现了删边,我们首先想到反向加边(如星球大战

那么最后的答案就是\(m-ans\)\(ans\)为加入的边

考虑一个边权为\(w\)的边\(E(u,v)\)

它是合法的,当且仅当\(u\)所在连通块与\(v\)所在连通块的点权之和大于\(w\)

我们思考一下,如果它是合法的,将会给答案带来什么影响

我们能够发现,边权\(\leq w\)的边,如果能与\(E\)在同一连通块中,那么它们都会因为\(E\)的加入而变得合法(无论它们之前合法与否)

那么这就给了我们启示:我们应该从小到大加边

对于一个在当前不合法的边,我们不能直接舍弃,因为它有可能因为后来加入的某些边而变得合法

因此我们开一个数组\(cnt\),用来记录某个连通块内目前不合法的边的数量

当我们遇到一条当前合法的边,我们把它加入答案,并且把其连接的两个连通块内的\(cnt\)数组也一并计入答案,因为此时它们因为这条边而变得合法了

维护连通块的操作用并查集实现,维护连通性与点权和,代码也很简单


代码

#include <cstdio>
#include <algorithm>

using namespace std;

const int N = 1e5 + 10;

struct edge {
    int u, v, w;
    bool operator < (const edge &x) const {
        return w < x.w; 
    }
} e[N]; 

int n, m, ans;
int sum[N], cnt[N];

int id[N];

inline int get(int x) {
    return x == id[x] ? x : id[x] = get(id[x]); 
}

int main() {
    
    scanf("%d%d", &n, &m);
    
    for (int i = 1; i <= n; ++i)    
        scanf("%d", sum + i);
    for (int i = 1; i <= m; ++i)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    
    sort(e + 1, e + m + 1);
    
    for (int i = 1; i <= n; ++i)    id[i] = i;
    
    for (int i = 1; i <= m; ++i) {
        int u = e[i].u, v = e[i].v;
        int fu = get(u), fv = get(v);
        if (fu != fv) {
            sum[fu] += sum[fv];
            cnt[fu] += cnt[fv];
            cnt[fv] = sum[fv] = 0;
            id[fv] = fu;    
        }
        cnt[fu]++;
        if (sum[fu] >= e[i].w) {
            ans += cnt[fu];
            cnt[fu] = 0;
        }
    }
    
    printf("%d\n", m - ans);
    
    return 0;
}

Atcoder Nikki Qual E Bridge

标签:print   星球大战   维护   sort   tor   struct   启示   数组   include   

原文地址:https://www.cnblogs.com/VeniVidiVici/p/11443700.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!