试题链接:https://ac.nowcoder.com/acm/contest/1221/H
/*
 思路:
 (1)将边从大到小排序
 (2)对于相同权值的边统一考虑,若这条边上两点不连通开始全部加入ans中,然后再考虑重复加入的情况,也是逐渐加入这些权值相同的边,若两点不连通
 ans-=w;否则说明这条边不唯一,应该删去

 要形成最小生成树,那么就没有别的边可以在构造最小生成树时加入最小生成树
 (对于相同权值的边统一考虑,若这条边上两点不连通开始全部加入ans中,然后再考虑重复加入的情况,
 也是逐渐加入这些权值相同的边
 若两点不连通ans-=w,否则说明这条边不唯一,应该删去)
 我们可以在计算最小生成树时,求所有可以加入最小生成树的边权和,再减去一个最小生成树的边权和就是答案
 */
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <vector>
#include <stack>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stdlib.h>
typedef long long ll;
using namespace std;

const int MaxN = 200005;

struct edge
{
    int u, v, w;
}E[MaxN];

bool cmp(edge x ,edge y) //下面要把每条边按照权值排序,就是一个结构体b排序,可以直接在sort里面加cmp,就不用写重载操作函数了
{
    return x.w<y.w;
}

int N, M;
long long Ans;
int Pre[MaxN];

void init() //初始化
{
    cin >> N >> M;//图的点数和边数
    for (int i = 1; i <= M; ++i)
    {
        cin >> E[i].u >> E[i].v >> E[i].w; //u,v表示两个端点,w表示权值(定义删除一条边的代价为w)
    }
}

int find(int i)
{
    if(i==Pre[i]) return i;
    else return Pre[i]=find(Pre[i]);
}

void solve()
{
    //M为边数,N为点数
    sort(E+1,E+1+M,cmp); //M为边数
    for (int i = 1; i <= N; ++i) //各自为自己的祖先
    {
        Pre[i] = i;
    }
    for (int i = 1; i <= M; ++i) //M次循环,M条边,i表示边数
    {
        //如果 前一条边 跟 后一条边 的值相等,就直接continue
        if (i == M || E[i].w != E[i + 1].w) //如果i是最后一条边 或者 第i条边的值不等于第i+1条边的值
        {

            for (int j = i;  j>=1 && E[j].w == E[i].w;  j--) //从那个当前这条边不断往上找
            {
                int u=E[j].u;
                int v=E[j].v;
                int w=E[j].w;
                int fu=find(u);
                int fv=find(v);
                //如果两条边在一个连通分量中,continue
                if(fv==fu) continue; //如果两条边不在一个连通分量中,答案加上E[i].w(先把所有权值相等的边加到ans中)
                Ans += w; //在这里不用将边的两点的祖先连在一起
            }

            for (int j = i;   j>=1&&E[j].w==E[i].w ;   j--)
            {
                int u=E[j].u;
                int v=E[j].v;
                int fu=find(u);
                int fv=find(v);
                if(fu==fv) continue;
                Pre[find(u)] = find(v); //将两者连在一起
                Ans -= E[i].w;
            }
        }
    }
    cout << Ans << endl;
}

int main()
{
    init();
    solve();
    return 0;
}