解题思路:
题目要求的是严格次小生成树。
先说说不严格次小生成树怎么做。
先求最小生成树。然后枚举每一条不最小生成树上的边(x,y,len),那么如果要把这条边压入树中,肯定要删除原树中的一条边。由于要使新树最小,所以删除的只能是原树中x到y路径上的最大边mx1,可以用倍增来求。那么新树大小即为totlen-mx1+len。对所有边进行该操作,取最小值就是答案。
那如何求严格次小呢?
其实还是一样的思路,再多找一个x到y路径上的严格次小边mx2,如果len>mx1,那么那么新树大小即为totlen-mx1+len;如果len==mx1,那那么那么新树大小即为totlen-mx2+len。最后还是取最小值。
时间复杂度为O(nlogn)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;
int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
const int N=100005,M=300005;
struct node
{
int x,y,w;
inline friend bool operator < (const node &a,const node &b)
{
return a.w<b.w;
}
}bian[M];
int n,m;
int id[N],fa[N][20],mx1[N][20],mx2[N][20],dep[N];
int tot,first[N],nxt[N<<1],to[N<<1],w[N<<1];
ll totlen,ans;
bool chs[M];
void add(int x,int y,int z)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,w[tot]=z;
}
int find(int x)
{
return id[x]==x?x:id[x]=find(id[x]);
}
void kruskal()
{
for(int i=1;i<=n;i++)id[i]=i;
sort(bian+1,bian+m+1);
int cnt=0;
for(int i=1;i<=m;i++)
{
int x=find(bian[i].x),y=find(bian[i].y);
if(x!=y)
{
cnt++;
totlen+=bian[i].w;
chs[i]=true;
add(bian[i].x,bian[i].y,bian[i].w);
add(bian[i].y,bian[i].x,bian[i].w);
id[y]=x;
if(cnt==n-1)break;
}
}
}
void dfs(int u)
{
for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=1;i<20;i++)mx1[u][i]=max(mx1[u][i-1],mx1[fa[u][i-1]][i-1]);
for(int i=1;i<20;i++)
{
mx2[u][i]=max(mx2[u][i-1],mx2[fa[u][i-1]][i-1]);
if(mx1[u][i-1]<mx1[fa[u][i-1]][i-1]&&mx2[u][i]<mx1[u][i-1])
mx2[u][i]=mx1[u][i-1];
if(mx1[u][i-1]>mx1[fa[u][i-1]][i-1]&&mx1[fa[u][i-1]][i-1]>mx2[u][i])
mx2[u][i]=mx1[fa[u][i-1]][i-1];
}
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];
if(v==fa[u][0])continue;
fa[v][0]=u;mx1[v][0]=w[e];
dep[v]=dep[u]+1;
dfs(v);
}
}
int Find(int x,int y,int len)
{
int Mx1=0,Mx2=0;
if(dep[x]<dep[y])swap(x,y);
int delta=dep[x]-dep[y];
for(int i=19;i>=0;i--)
if(delta&(1<<i))
{
if(Mx1>mx1[x][i]&&mx1[x][i]>Mx2)Mx2=mx1[x][i];
if(Mx1<mx1[x][i])Mx2=max(Mx1,mx2[x][i]),Mx1=mx1[x][i];
x=fa[x][i];
}
if(x==y)return Mx1==len?Mx2:Mx1;
for(int i=19;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
if(Mx1>mx1[x][i]&&mx1[x][i]>Mx2)Mx2=mx1[x][i];
if(Mx1<mx1[x][i])Mx2=max(Mx1,mx2[x][i]),Mx1=mx1[x][i];
x=fa[x][i];
if(Mx1>mx1[y][i]&&mx1[y][i]>Mx2)Mx2=mx1[y][i];
if(Mx1<mx1[y][i])Mx2=max(Mx1,mx2[y][i]),Mx1=mx1[y][i];
y=fa[y][i];
}
if(Mx1>mx1[x][0]&&mx1[x][0]>Mx2)Mx2=mx1[x][0];
if(Mx1<mx1[x][0])Mx2=max(Mx1,mx2[x][0]),Mx1=mx1[x][0];
x=fa[x][0];
if(Mx1>mx1[y][0]&&mx1[y][0]>Mx2)Mx2=mx1[y][0];
if(Mx1<mx1[y][0])Mx2=max(Mx1,mx2[y][0]),Mx1=mx1[y][0];
y=fa[y][0];
return Mx1==len?Mx2:Mx1;
}
void solve(int e)
{
int x=bian[e].x,y=bian[e].y,len=bian[e].w;
int tmp=Find(x,y,len);
ans=min(ans,totlen-tmp+len);
}
int main()
{
//freopen("lx.in","r",stdin);
n=getint(),m=getint();
for(int i=1;i<=m;i++)
{
bian[i].x=getint();
bian[i].y=getint();
bian[i].w=getint();
}
kruskal();
dfs(1);
ans=1e18;
for(int i=1;i<=m;i++)
if(!chs[i])solve(i);
printf("%lld",ans);
}