今天跟大家聊聊怎么求次小生成树。
首先需要注意的是我们所说的次小生成树是指严格次小生成树。也就是我们要求的是权值大于最小生成树的权值最小的生成树。
我们求次小生成树是基于最小生成树的。我们求出最小生成树,那么显然次小生成树只会改变最小生成树上的一条边。
所以我们枚举每条非最小生成树上的边,那么我们只要从这条边的两点在树上的树链里求出权值最大的一条边,然后加入这条边的生成树就是原来的值num加上这条边的值val,再减去链上最大值max。
但是我们要求的是严格的,所以得保证max< val,然而有时会出现max==val的情况。所以我们不仅要记录树链的最大值,还要记录树链上的次大值(当然得小与最大值)。
问题在于怎么维护,维护的方法有多种多样,这里我选择了倍增+LCA的方法,就是用倍增来求并记录值。当然也可以用树剖写。
维护次大值确实很烦,导致代码又臭又长。
//Ma记录最大值,Tw记录次大值,gran就是祖先
using namespace std;
ll read(){
char c;ll x;while(c=getchar(),c<'0'||c>'9');x=c-'0';
while(c=getchar(),c>='0'&&c<='9') x=x*10+c-'0';return x;
}
ll n,m,k,cnt,ans,tot,fa[MAX],head[MAXN],nxt[MAXN],Ma[MAXN][10],Tw[MAXN][10],dep[MAXN],gran[MAXN][10];
struct edge{
ll to,val;
}L[MAXN];
struct node{
ll a,b,len,vis;
}F[MAXN];
ll cmp(node a,node b){
return a.len<b.len;
}
ll find(ll x){
if(fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
void add(ll x,ll y,ll c){
L[cnt]=(edge){y,c};
nxt[cnt]=head[x];head[x]=cnt;cnt++;
L[cnt]=(edge){x,c};
nxt[cnt]=head[y];head[y]=cnt;cnt++;
}
void dfs(ll x,ll fa){
for(ll i=head[x];i!=-1;i=nxt[i]){
ll to=L[i].to;
if(dep[to]) Ma[x][0]=L[i].val;
}
dep[x]=dep[fa]+1;gran[x][0]=fa;
for(ll i=1;(1<<i)<=dep[x];i++){
gran[x][i]=gran[gran[x][i-1]][i-1];
if(Ma[x][i-1]<Ma[gran[x][i-1]][i-1]){
Ma[x][i]=Ma[gran[x][i-1]][i-1];
Tw[x][i]=max(Ma[x][i-1],Tw[gran[x][i-1]][i-1]);
}
else{
Ma[x][i]=Ma[x][i-1];
if(Ma[gran[x][i-1]][i-1]<Ma[x][i-1]) Tw[x][i]=max(Tw[x][i-1],Ma[gran[x][i-1]][i-1]);
else Tw[x][i]=max(Tw[x][i-1],Tw[gran[x][i-1]][i-1]);
}
}
for(ll i=head[x];i!=-1;i=nxt[i]){
ll to=L[i].to;
if(!dep[to]) dfs(to,x);
}
}
pair<ll,ll> LCA(ll x,ll y){
ll m1=0,m2=0;
if(dep[x]>dep[y]) swap(x,y);
for(ll i=9;i>=0;i--)
if(dep[gran[y][i]]>=dep[x]){
if(Ma[y][i]>m1) m2=m1,m1=Ma[y][i];
else if(Ma[y][i]<m1&&Ma[y][i]>m2) m2=Ma[y][i];
if(Tw[y][i]<m1&&Tw[y][i]>m2) m2=Tw[y][i];
y=gran[y][i];
}
for(ll i=9;i>=0;i--)
if(gran[x][i]!=gran[y][i]){
if(Ma[x][i]>Ma[y][i]){
if(Ma[x][i]>m1) m2=m1,m1=Ma[x][i];
if(Ma[x][i]<m1&&Ma[x][i]>m2) m2=Ma[x][i];
if(max(Tw[x][i],Ma[y][i])>m2){
m2=max(Tw[x][i],Ma[y][i]);
}
}
else{
if(Ma[y][i]>m1) m2=m1,m1=Ma[y][i];
if(Ma[x][i]<m1&&Ma[x][i]>m2) m2=Ma[x][i];
if(max(Ma[x][i],Tw[y][i])>m2){
if(max(Ma[x][i],Tw[y][i])<m1) m2=max(Ma[x][i],Tw[y][i]);
else m2=max(Tw[x][i],Tw[y][i]);
}
}
x=gran[x][i];y=gran[y][i];
}
if(x!=y){
if(Ma[y][0]>m1) m2=m1,m1=Ma[y][0];
else if(Ma[y][0]<m1&&Ma[y][0]>m2) m2=Ma[y][0];
if(Tw[y][0]>m2) m2=Tw[y][0];
if(Ma[x][0]>m1) m2=m1,m1=Ma[x][0];
else if(Ma[x][0]<m1&&Ma[x][0]>m2) m2=Ma[x][0];
if(Tw[x][0]>m2) m2=Tw[x][0];
}
return make_pair(m1,m2);
}
int main()
{
n=read();m=read();ans=1e18;
memset(head,-1,sizeof(head));
for(ll i=1;i<=m;i++){
ll a=read(),b=read(),c=read();
F[i]=(node){a,b,c};
}
sort(F+1,F+1+m,cmp);
for(ll i=1;i<=n;i++) fa[i]=i;
for(ll i=1;i<=m;i++){
if(k==n-1) break;
ll fx=find(F[i].a),fy=find(F[i].b);
if(fx!=fy){
fa[fy]=fx;k++;F[i].vis=1;tot+=F[i].len;
add(F[i].a,F[i].b,F[i].len);
}
}
dfs(1,0);
for(ll i=1;i<=m;i++){
if(F[i].vis) continue;
pair<ll,ll> e=LCA(F[i].a,F[i].b);
if(e.first<F[i].len) ans=min(ans,tot+F[i].len-e.first);
else ans=min(ans,tot+F[i].len-e.second);
}
printf("%lld",ans);
return 0;
}