最小生成树,LCA
次小生成树必定是从最小生成树中删掉一条边,再加入一条不会成环的边即可。
预处理出每个点到其祖先的路径上的最大边以及次大边。
那么我们可以枚举每条非树边,如果这条边比u,v路上的所有边都大的话,则可以替换掉最大的边作为次小生成树的备选。
如果该边与最大边相等,那么可以用该边替换掉路径中的次大边,作为备选答案。
预处理最大边及次大边的话我们需要在bfs处理节点上翻中加入一些东西。来,看书 《算法竞赛进阶指南》--李煜东著
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
const int maxm=3e5+7;
const int inf=0x3f3f3f3f;
struct Edge{
int v,w,next;
}edge[maxn<<1];
int head[maxn],top;
void add(int u,int v,int w){
edge[top].v=v;
edge[top].w=w;
edge[top].next=head[u];
head[u]=top++;
}
int fre[maxn];
struct Node{
int u,v,w;
bool f;
bool operator <(const Node& x)const{ return w<x.w; }
}a[maxm];
void init(){
memset(head,-1,sizeof(head));
top=0;
for(int i=0;i<maxn;++i) fre[i]=i;
}
int myfind(int x){
int r=x;
while(r!=fre[r]) r=fre[r];
int i=x,j;
while(i!=r){
j=fre[i];
fre[i]=r;
i=j;
}
return r;
}
bool liantong(int x,int y){
int fx=myfind(x);
int fy=myfind(y);
if(fx!=fy){
fre[fx]=fy;
return 1;
}
return 0;
}
int mi=18;
int d[maxn],dis1[maxn][22],dis2[maxn][22],fa[maxn][22];
queue<int> q;
void bfs(int st){
while(!q.empty()) q.pop();
d[st]=1;
dis1[st][0]=0;
dis2[st][0]=-1;
q.push(st);
int u,v,w;
while(!q.empty()){
u=q.front(); q.pop();
for(int i=head[u];i!=-1;i=edge[i].next){
v=edge[i].v;
w=edge[i].w;
if(d[v]) continue;
d[v]=d[u]+1;
dis1[v][0]=w;
dis2[v][0]=-1;
fa[v][0]=u;
for(int j=1;j<=mi;++j){
fa[v][j]=fa[fa[v][j-1]][j-1];
dis1[v][j]=max(dis1[v][j-1],dis1[fa[v][j-1]][j-1]);
if(dis1[v][j-1]==dis1[fa[v][j-1]][j-1])
dis2[v][j]=max(dis2[v][j-1],dis2[fa[v][j-1]][j-1]);
else if(dis1[v][j-1]<dis1[fa[v][j-1]][j-1])
dis2[v][j]=max(dis1[v][j-1],dis2[fa[v][j-1]][j-1]);
else
dis2[v][j]=max(dis2[v][j-1],dis1[fa[v][j-1]][j-1]);
}
q.push(v);
}
}
}
pair<int,int> LCA(int x,int y){
if(d[x]>d[y]) swap(x,y);
int v1=-1,v2=-1;
for(int i=mi;i>=0;--i)
if(d[fa[y][i]]>=d[x]){
if(v1>dis1[y][i]){
v2=max(v2,dis1[y][i]);
}
else{
v1=dis1[y][i];
v2=max(v2,dis2[y][i]);
}
y=fa[y][i];
}
if(x==y) return make_pair(v1,v2);
for(int i=mi;i>=0;--i){
if(fa[y][i]!=fa[x][i]){
if(v1>dis1[x][i]) v2=max(v2,dis1[x][i]);
else v1=dis1[x][i],v2=max(v2,dis2[x][i]);
if(v1>dis1[y][i]) v2=max(v2,dis1[y][i]);
else v1=dis1[y][i],v2=max(v2,dis2[y][i]);
x=fa[x][i];
y=fa[y][i];
}
}
if(v1>dis1[x][0]) v2=max(v2,dis1[x][0]);
else v1=dis1[x][0],v2=max(v2,dis2[x][0]);
if(v1>dis1[y][0]) v2=max(v2,dis1[y][0]);
else v1=dis1[y][0],v2=max(v2,dis2[y][0]);
return make_pair(v1,v2);
}
pair<int,int> p;
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;++i){
scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w);
}
int f=0;
init();
sort(a,a+m);
ll sum=0;
for(int i=0;i<m;++i){
if(liantong(a[i].u,a[i].v)){
add(a[i].u,a[i].v,a[i].w);
a[i].f=1;
add(a[i].v,a[i].u,a[i].w);
sum+=a[i].w;
++f;
if(f==n-1) break;
}
}
bfs(1);
ll res=0x3f3f3f3f3f3f3f3f;
for(int i=0;i<m;++i)
if(a[i].f==0){
p=LCA(a[i].u,a[i].v);
int v1=p.first,v2=p.second;
if(a[i].w>v1) res=min(res,sum-v1+a[i].w);
else if(a[i].w==v1) res=min(res,sum-v2+a[i].w);
}
printf("%lld\n",res);
return 0;
}