原文链接:https://blog.youkuaiyun.com/BerryKanry/article/details/77983140
题目大意:求严格次小生成树
#include<stdio.h>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
typedef long long dnt;
const int INF=0x3f3f3f3f;
struct edge
{
int u,v,w,last;
}ed[2000010],sid[2000010];
int n,m,num=0,tot=0,ans=INF;
int head[100010],fa[100010],dep[100010];
int anc[100010][20],st[100010][20],sd[100010][20],used[300010];
dnt bns=0;
bool cmp(const edge &a,const edge &b)
{
return a.w<b.w;
}
void add(int u,int v,int w)
{
num++;
ed[num].v=v;
ed[num].w=w;
ed[num].last=head[u];
head[u]=num;
}
int getfather(int x)
{
if(x==fa[x]) return x;
return fa[x]=getfather(fa[x]);
}
void Kruscal()
{
sort(sid+1,sid+m+1,cmp);
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
{
int x=getfather(sid[i].u),y=getfather(sid[i].v);
if(x!=y)
{
used[i]=1;
tot++,bns+=sid[i].w;
add(sid[i].u,sid[i].v,sid[i].w);
add(sid[i].v,sid[i].u,sid[i].w);
fa[x]=y;
}
if(tot==n-1) return ;
}
return ;
}
void dfs(int u,int f)
{/// 这个代码的精华所在
anc[u][0]=f;
for(int p=1;p<=16;p++)
{
anc[u][p]=anc[anc[u][p-1]][p-1],/// 祖先部分
st[u][p]=max(st[u][p-1],st[anc[u][p-1]][p-1]);/// 最大值部分(显然 ST表)
if(st[u][p-1]==st[anc[u][p-1]][p-1])
sd[u][p]=max(sd[u][p-1],sd[anc[u][p-1]][p-1]);/// 到祖先的两部分如果最大值都相等的话 那么直接从两部分的次大值转移过来一定没错
else
{
sd[u][p]=min(st[u][p-1],st[anc[u][p-1]][p-1]);///要么是两个最大值的较小的
sd[u][p]=max({sd[u][p],sd[u][p-1],sd[anc[u][p-1]][p-1]});///还要考虑是否有一部分的次小时大于上面的那个较小的最大值
}
}
for(int i=head[u];i;i=ed[i].last)
{
int v=ed[i].v;
if(v==f) continue ;
dep[v]=dep[u]+1;
st[v][0]=ed[i].w;
dfs(v,u);
}
}
void calmx(int wth,int vth,int &d,int &e)
{
if(wth==d) return ;
if(wth>d) e=d,d=wth;
else if(wth>e) e=wth;
e=max(e,vth);
}
int lca(int u,int v,int xx)
{
int d=0,e=0;
if(dep[u]<dep[v]) swap(u,v);
for(int i=16;i>=0;i--)
if(dep[anc[u][i]]>=dep[v])
{
calmx(st[u][i],sd[u][i],d,e);
u=anc[u][i];
}
if(u==v)
{
if(xx==d) return e;
return d;
}
for(int i=16;i>=0;i--)
if(anc[u][i]!=anc[v][i])
{
calmx(st[u][i],sd[u][i],d,e);calmx(st[v][i],sd[u][i],d,e);
u=anc[u][i],v=anc[v][i];
}
calmx(st[u][0],sd[u][0],d,e),calmx(st[v][0],sd[v][0],d,e);
if(xx==d) return e;
return d;
}
int main()
{
// freopen("input2.txt","r",stdin);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&sid[i].u,&sid[i].v,&sid[i].w);
Kruscal();
dfs(1,1);
for(int i=1;i<=m;i++)
{
if(used[i]) continue ;
int u=sid[i].u,v=sid[i].v;
int tmp=lca(u,v,sid[i].w);
ans=min(ans,sid[i].w-tmp);
}
cout << ans+bns <<endl ;
return 0;
}