【JZOJ4629】修路

Description

这里写图片描述

Solution

很显然,如果要取一条边 (u,v) ,那么贡献值就会增加 (au+av) ,于是我们把所有边的边权减去边两边端点的 ax ,然后我们会得到一些互不影响的边权,于是跑一次最小生成树即可。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 100001
#define ll long long
using namespace std;
ll a[N];
struct node{
    int x,y;
    ll z;
}b[N];
bool cmp(node x,node y)
{
    return x.z<y.z;
}
int f[N];
int find(int x)
{
    return !f[x]?x:f[x]=find(f[x]);
}
int main()
{
    freopen("2.in","r",stdin);
    freopen("2.out","w",stdout);
    int n,m;
    cin>>n>>m;
    fo(i,1,n) scanf("%lld",&a[i]);
    fo(i,1,m)
    {
        int x,y;
        ll z;
        scanf("%d %d %lld",&x,&y,&z);
        b[i].x=x;
        b[i].y=y;
        b[i].z=z-a[x]-a[y];
    }
    sort(b+1,b+m+1,cmp);
    int cnt=0;
    ll ans=0;
    fo(i,1,m)
    {
        int fx=find(b[i].x),fy=find(b[i].y);
        if(fx!=fy)
        {
            f[fy]=fx;
            ans+=b[i].z;
            cnt++;
            if(cnt==n-1) break;
        }
    }
    cout<<ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值