b_lg_按位奶牛(预处理点权和边权)

john走访完所有的奶牛之后,还要回到他的出发地。
每次路过牧场i的时候,john必须花Ci的时间和奶牛交谈,即使之前已经做过工作
请你计算一下,约翰要拆除哪些道路,才能让谈话(忽悠)奶牛的时间变得最少?

知道是MST,但回程难以模拟,故直接将边权设为:边权*2+两个端点的点权
注:由于和起点相连的边一开始就被加到一个连通块中,假如起点出度为2,则起点需要被经过3次才对,但kruskal只会算两次,故还要加上最小的点权(起点的点权)

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5, M=1e6+5;
int n,m,fa[N],c[N];
struct edge {
    int u,v,w;
}e[M];
int find(int u) {return fa[u]==u ? u : fa[u]=find(fa[u]);}
int kruskal() {
    for (int i=1; i<=n; i++) fa[i]=i;
    sort(e,e+m,[&](edge a, edge b){return a.w<b.w;});
    int ans=0;
    for (int i=0; i<m; i++) {
        int fu=find(e[i].u), fv=find(e[i].v);
        if (fu!=fv) {
            fa[fu]=fv;
            ans+=e[i].w;
        }
    }
    return ans;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin>>n>>m;
    for (int i=1; i<=n; i++) cin>>c[i];
    for (int i=0; i<m; i++) cin>>e[i].u>>e[i].v>>e[i].w, e[i].w=2*e[i].w+c[e[i].u]+c[e[i].v];
    cout<<*min_element(c+1,c+n+1)+kruskal();
    return 0;
}

我的疑惑:kruskal不是按照边权+点权排序的吗?那约束有两个啊,万一和点权很小的点连接的边权很大(那就不是起点了啊),那这个额外加不就错了吗

原文地址:https://www.cnblogs.com/wdt1/p/13815653.html