luogu 2700 逐个击破

Description

    现在有 N 个城市,其中 K 个被敌方军团占领了,N 个城市间有 N - 1 条公路相连,破坏其中某条公路的代价是已知的,现在,告诉你 K 个敌方军团所在的城市,以及所有公路破坏的代价,请你算出花费最少的代价将这 K 个地方军团互相隔离开,以便第二步逐个击破敌人。

Input

第一行包含两个正整数 n 和 k。

第二行包含 k 个整数,表示哪个城市别敌军占领。

接下来 n - 1 行,每行包含三个正整数 a, b, c,表示从 a 城市到 b 城市有一条公路,以及破坏的代价 c。城市的编号从 0 开始。

Output

输出一行一个整数,表示最少花费的代价。

Sample Input

5 3
1 2 4
1 0 4
1 3 8
2 1 1
2 4 3

Sample Output

4

Hint

10% 的数据: 2n10

100% 的数据: 2n1000002kn1c1000000


Solution :

    我们可以转化一下,不是要使他们不连通吗,而且减去最小边,我们可以反过来想,建一片最大森林,原树的边权总和减去最大森林的和就是我们要的答案,写法和最大生成树一样,只是打个标记,我这里的是 vis


Code :

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#define LL long long
using namespace std;

inline int read() {
    int i = 0, f = 1;
    char ch = getchar();
    while(!isdigit(ch)) {
        if(ch == '-') f = -1; ch = getchar();
    }
    while(isdigit(ch)) {
        i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
    }
    return i * f;
}

const int MAXN = 1e5 + 5;
int fa[MAXN], vis[MAXN];

struct point {
    int from, to;
    LL w;
    inline bool operator < (const point & a) const {
        return w > a.w;
    }
};
point e[MAXN];

inline int getfather(int x) {
    return fa[x] == x ? x : fa[x] = getfather(fa[x]);
}

int main() {
    LL ans = 0;
    int n = read(), k = read();
    for(int i = 1; i <= n; ++i) fa[i] = i;
    for(int i = 1; i <= k; ++i) vis[read() + 1] = 1;
    for(int i = 1; i <= n - 1; ++i) 
        e[i].from = read() + 1, e[i].to = read() + 1, e[i].w = (LL)read(), ans += e[i].w;
    sort(e + 1, e + n);
    for(int i = 1; i <= n - 1; ++i) {
        int gx = getfather(e[i].from);
        int gy = getfather(e[i].to);
        if(vis[gx] + vis[gy] == 2) continue;
        if(gx == gy) continue;
        int now = vis[gx] + vis[gy];
        vis[gx] = now, vis[gy] = now;
        fa[gx] = gy;
        ans -= e[i].w;
    }
    cout<<ans<<'\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值