Problem
![在这里插入图片描述](https://img-blog.csdnimg.cn/270a2ab80d9f4c9287417b41f9a07b0f.png#pic_center)
Solution
- 做法与求非严格次小生成树类似(枚举非mst上的边来替换mst上的边)。
- 需要同时维护最大边和严格次大边的倍增数组,不存在严格次大边的情况下需设为-inf,保证此次计算不会作为最终答案。
- 关于严格次大边倍增数组的递推:取左右区间严格次大边的max,同时若左右区间的最大边不相等,两区间最大边的最小值。
- 关于求树上两点间的严格次大边:假设待加入边权值为w,每次更新时若区间最大边<w,则用区间最大边更新,否则用区间的严格次大边更新。
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=2e5,maxm=300005;
const int inf = 1e9+5;
int t,n,m,cnt,logg[maxn],f[maxn],pre[maxn][35],dep[maxn];
long long mx[maxn][35],fmx[maxn][35],mst;
bool used[maxm];
struct edge{
int u,v,w;
}e[maxm];
struct node{
int u,w;
};
vector<node>q[maxn];
bool cmp(const edge &a,const edge &b)
{
return a.w<b.w;
}
inline void add(int u,int v,int w)
{
e[++cnt].v=v;
e[cnt].w=w;
e[cnt].u=u;
}
int find(int x)
{
return f[x]==x?x:f[x]=find(f[x]);
}
void kruskal()
{
int k = 0;
sort(e+1,e+1+m,cmp);
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
if(find(u)!=find(v))
{
k++;
mst+=w;
f[find(u)]=f[find(v)];
used[i] = 1;
q[u].push_back({v,w});
q[v].push_back({u,w});
if(k==n-1) return ;
}
}
}
void dfs(int u,int fa)
{
for(int i=1;i<=18;i++)
{
pre[u][i]=pre[pre[u][i-1]][i-1];
mx[u][i]=max(mx[u][i-1],mx[pre[u][i-1]][i-1]);
fmx[u][i]=max(fmx[u][i-1],fmx[pre[u][i-1]][i-1]);
if(mx[u][i-1]>mx[pre[u][i-1]][i-1]) fmx[u][i]=max(fmx[u][i],mx[pre[u][i-1]][i-1]);
else if(mx[u][i-1]<mx[pre[u][i-1]][i-1]) fmx[u][i]=max(fmx[u][i],mx[u][i-1]);
}
for(int i=0;i<q[u].size();i++)
{
int v=q[u][i].u,w=q[u][i].w;
if(v!=fa)
{
mx[v][0]=w;
fmx[v][0]=-inf;
pre[v][0]=u;
dep[v]=dep[u]+1;
dfs(v,u);
}
}
}
long long lcaw(int x,int y,int w)
{
long long maxw = -1e18;
if(dep[x]<dep[y])
swap(x,y);
while(dep[x]!=dep[y])
{
if(mx[x][logg[dep[x]-dep[y]]]!=w)
maxw=max(maxw,mx[x][logg[dep[x]-dep[y]]]);
else
maxw=max(maxw,fmx[x][logg[dep[x]-dep[y]]]);
x=pre[x][logg[dep[x]-dep[y]]];
}
if(x==y)
return maxw;
for(int k=logg[dep[x]];k>=0;k--)
if(pre[x][k]!=pre[y][k])
{
maxw=mx[x][k]!=w?max(maxw,mx[x][k]):max(maxw,fmx[x][k]);
maxw=mx[y][k]!=w?max(maxw,mx[y][k]):max(maxw,fmx[y][k]);
x=pre[x][k],y=pre[y][k];
}
maxw=mx[x][0]!=w?max(maxw,mx[x][0]):maxw;
maxw=mx[y][0]!=w?max(maxw,mx[y][0]):maxw;
return maxw;
}
long long SMST()
{
long long smst = 1e18;
for(int i=1;i<=m;i++)
{
int u=e[i].u,v=e[i].v,w=e[i].w;
if(!used[i])
smst=min(smst,mst+w-lcaw(u,v,w));
}
return smst;
}
int main()
{
t = 1;
for(int i=2;i<=100005;i++)
logg[i]=logg[i-1]+((1<<(logg[i-1]+1))==i);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
f[i]=i;
for(int i=1,u,v,w;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
kruskal();
dfs(1,0);
cout<<SMST()<<endl;
}
return 0;
}