求严格次小生成树
用倍增记录最小值和次小值+求lca,枚举每一条非树边,然后转移更新
PS:dfs时注意最小值和次小值的转移
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=1e5+10,M=3e5+10;
const int inf=0x7fffffff;
int n,m,len=0,last[N],
f[N][20],mx_1[N][20],mx_2[N][20],dep[N],Fa[N],vis[N];
ll ans=0,mn=inf;
struct Edge{ll from,to,next,val;Edge(ll from=0,ll to=0,ll next=0,ll val=0):from(from),to(to),next(next),val(val){}}e[N<<1];
struct Data{
ll from,to,val;
Data(ll from=0,ll to=0,ll val=0):from(from),to(to),val(val){}
bool operator <(const Data &rhs)const {
return rhs.val>val;
}
}E[M];
void add_edge(ll u,ll v,ll w){e[++len]=Edge(u,v,last[u],w);last[u]=len;}
ll find(ll x){return x==Fa[x]?Fa[x]:Fa[x]=find(Fa[x]);}
void Kruskal()
{
int tot=0;
fo(i,1,n)Fa[i]=i;
for(int i=1;i<=m;i++) {
ll p=find(E[i].from),q=find(E[i].to);
if(p!=q){
Fa[p]=q;
ans+=E[i].val;
vis[i]=1;
add_edge(E[i].from,E[i].to,E[i].val);
add_edge(E[i].to,E[i].from,E[i].val);
tot++;if(tot==n-1)break;
}
}
}
#define d1 mx_1
#define d2 mx_2
void dfs(int u,int fa)
{
for(int i=1;i<=16;i++) {
if(dep[u]<(1<<i))break;
f[u][i]=f[f[u][i-1]][i-1];
mx_1[u][i]=max(mx_1[u][i-1],mx_1[f[u][i-1]][i-1]);
if(mx_1[u][i-1]==mx_1[f[u][i-1]][i-1])
mx_2[u][i]=max(mx_2[u][i-1],mx_2[f[u][i-1]][i-1]);
else {
mx_2[u][i]=min(mx_1[u][i-1],mx_1[f[u][i-1]][i-1]);
mx_2[u][i]=max(mx_2[u][i],max(mx_2[u][i-1],mx_2[f[u][i-1]][i-1]));
}
}
for(int i=last[u];i;i=e[i].next) {
int id=e[i].to;
if(id==fa)continue;
f[id][0]=u;dep[id]=dep[u]+1;
mx_1[id][0]=e[i].val;
dfs(id,u);
}
}
ll lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
int d=dep[x]-dep[y];
for(int i=0;i<=16;i++)
if(d&(1<<i)) {x=f[x][i];}
for(int i=16;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
if(x==y)return x;
else return f[x][0];
}
void cal(int x,int ff,int v)
{
int t=dep[x]-dep[ff],mx1=0,mx2=0;
for(int i=0;i<=16;i++){
if(t&(1<<i)){
if(d1[x][i]>mx1){
mx2=mx1;
mx1=d1[x][i];
}
mx2=max(mx2,d2[x][i]);
x=f[x][i];
}
}
if(mx1!=v)mn=min(mn,ll(v-mx1));
else mn=min(mn,ll(v-mx2));
}
void solve(int t)
{
int x=E[t].from,y=E[t].to,ff=lca(x,y),v=E[t].val;
cal(x,ff,v);cal(y,ff,v);
}
int main()
{
scanf("%d%d",&n,&m);
for(int u,v,w,i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
E[i]=Data(u,v,w);
}sort(E+1,E+1+m);
Kruskal();
dfs(1,0);
for(int i=1;i<=m;i++) if(!vis[i]) solve(i);
printf("%lld",ans+mn);
return 0;
}