n代表点m代表边,网上大佬的代码,先当模板了,感觉这也像是模板。。。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline int read(){
    int x=0,f=1;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<1)+(x<<3)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x>=10)  print(x/10);
    putchar(x%10+'0');
}
const int N=1e5,M=3e5;
int v[N+10],dfn[N+10],ID[N+10];
int n,m;
struct S1{
    #define ls (p<<1)
    #define rs (p<<1|1)
    struct node{
        int f,g;
        node(){f=g=-inf;}
        void insert(int _f,int _g){f=_f,g=_g;}
    }tree[(N<<2)+10];
    friend node operator +(const node &x,const node &y){
        node z;
        z.f=max(x.f,y.f);
        z.g=max(x.g,y.g);
        if (x.f!=y.f)   z.g=max(z.g,min(x.f,y.f));
        return z;
    }
    void build(int p,int l,int r){
        if (l==r){
            tree[p].insert(v[dfn[l]],-inf);
            return;
        }
        int mid=(l+r)>>1;
        build(ls,l,mid),build(rs,mid+1,r);
        tree[p]=tree[ls]+tree[rs];
    }
    node Query(int p,int l,int r,int x,int y){
        if (x<=l&&r<=y) return tree[p];
        int mid=(l+r)>>1; node res;
        if (x<=mid) res=res+Query(ls,l,mid,x,y);
        if (y>mid)  res=res+Query(rs,mid+1,r,x,y);
        return res;
    }
}ST;//Segment Tree
struct S2{
    int pre[(M<<1)+10],now[N+10],child[(M<<1)+10],val[(M<<1)+10];
    int top[N+10],Rem[N+10],deep[N+10],size[N+10],fa[N+10];
    int tot,Time;
    void join(int x,int y,int z){pre[++tot]=now[x],now[x]=tot,child[tot]=y,val[tot]=z;}
    void insert(int x,int y,int z){join(x,y,z),join(y,x,z);}
    void build(int x){
        deep[x]=deep[fa[x]]+1,size[x]=1;
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]) continue;
            fa[son]=x,v[son]=val[p];
            build(son),size[x]+=size[son];
            if (size[Rem[x]]<size[son]) Rem[x]=son;
        }
    }
    void dfs(int x){
        if (!x) return;
        dfn[ID[x]=++Time]=x;
        top[x]=Rem[fa[x]]==x?top[fa[x]]:x;
        dfs(Rem[x]);
        for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]){
            if (son==fa[x]||son==Rem[x])    continue;
            dfs(son);
        }
    }
    int Get(int x,int y,int z){
        S1::node res;
        while (top[x]!=top[y]){
            if (deep[top[x]]<deep[top[y]])  swap(x,y);
            res=res+ST.Query(1,1,n,ID[top[x]],ID[x]);//+被重载了,在ST结构体里面
            x=fa[top[x]];
        }
        if (x!=y){
            if (deep[x]>deep[y])    swap(x,y);
            res=res+ST.Query(1,1,n,ID[Rem[x]],ID[y]);
        }
        if (res.f==-inf&&res.g==-inf)   return inf;//开始没判,后面因为重边导致res两个信息都为-inf,于是炸int了。。。
        return z-(z==res.f?res.g:res.f);
    }
}HLD;//Heavy-Light Decomposition
struct S3{
    int fa[N+10];
    void init(){for (int i=1;i<=n;i++)  fa[i]=i;}
    int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
}DSU;//Disjoint Set Union
struct S4{
    int x,y,z,type;
    S4(){type=0;}
    void insert(){x=read(),y=read(),z=read();}
    bool operator <(const S4 &a)const{return z<a.z;}
}A[M+10];
int main(){
    n=read(),m=read();
    for (int i=1;i<=m;i++)  A[i].insert();
    sort(A+1,A+1+m);
    DSU.init();
    ll MST=0;int Ans=inf;
    for (int i=1;i<=m;i++){
        int x=DSU.find(A[i].x),y=DSU.find(A[i].y);
        if (x!=y)   DSU.fa[x]=y,HLD.insert(A[i].x,A[i].y,A[i].z),A[i].type=1,MST+=A[i].z;
    }
    HLD.build(1),HLD.dfs(1),ST.build(1,1,n);
    for (int i=1;i<=m;i++){
        if (A[i].type)  continue;
        Ans=min(Ans,HLD.Get(A[i].x,A[i].y,A[i].z));
    }
    printf("%lld\n",MST+Ans);
    return 0;
}