题意:求严格次小生成树,保证存在。
首先求出原图的最小生成树,我们先考虑次小生成树是怎么得来的,加入一条非树边后原先的树中就会出现一个环,用加入的那条边替换掉环上最大的树边,但这题并不能这么做,因为会出现环上最大的边=非树边的情况,所以我们既要找出环上的最大边,又要找出严格次大边,这个可以用树上倍增解决,因为我比较傻叉,所以写了个link-cut tree,勿喷…(其实LCT也不是很慢)
Tips:找严格次大边要注意,我WA了一发,还有开longlong
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
const int maxn=400000+10;
const int INF=1000000000;
int c[maxn][2],fa[maxn],v[maxn],mn[maxn],rev[maxn],st[maxn],tot,pa[maxn],n,m,flag[maxn],mn2[maxn];
long long ans=0,out=(long long)1000000000*(long long)1000000000;
struct edge
{
int u,v,c;
}e[maxn];
int cmp(edge a,edge b)
{
return a.c<b.c;
}
int find(int p)
{
if(pa[p]==p) return p;
else return pa[p]=find(pa[p]);
}
inline bool isroot(int x)
{
if(c[fa[x]][1]!=x&&c[fa[x]][0]!=x) return true;
else return false;
}
void pushup(int x)
{
int l=c[x][0],r=c[x][1];
mn[x]=v[x];mn2[x]=0;
if(l)
{
if(mn[l]>mn[x])
{
mn2[x]=max(mn2[l],mn[x]);
mn[x]=mn[l];
}
else if(mn[l]>mn2[x])
{
if(mn[l]<mn[x]) mn2[x]=mn[l];
else mn2[x]=max(mn2[x],mn2[l]);
}
}
if(r)
{
if(mn[r]>mn[x])
{
mn2[x]=max(mn2[r],mn[x]);
mn[x]=mn[r];
}
else if(mn[r]>mn2[x])
{
if(mn[r]<mn[x]) mn2[x]=mn[r];
else mn2[x]=max(mn2[x],mn2[r]);
}
}
}
void pushdown(int x)
{
int l=c[x][0],r=c[x][1];
if(rev[x])
{
rev[x]^=1;rev[l]^=1;rev[r]^=1;
swap(c[x][0],c[x][1]);
}
}
void rotate(int x)
{
int y=fa[x],z=fa[y],l,r;
if(c[y][0]==x) l=0;else l=1;r=l^1;
if(!isroot(y))
{
if(c[z][0]==y) c[z][0]=x;
else c[z][1]=x;
}
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;pushup(y);pushup(x);
}
void splay(int x)
{
int top=0;st[top=1]=x;
for(int i=x;!isroot(i);i=fa[i])
st[++top]=fa[i];
for(int i=top;i;i--) pushdown(st[i]);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(c[z][0]==y^c[y][0]==x) rotate(x);
else rotate(y);
}
rotate(x);
}
pushup(x);
}
void access(int x)
{
int t=0;
while(x)
{
splay(x);
c[x][1]=t;
t=x;x=fa[x];
}
}
void makeroot(int x)
{
access(x);splay(x);rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x);access(y);splay(y);fa[x]=y;pushup(y);
}
int querymax(int x,int y)
{
makeroot(x);access(y);splay(y);return mn[y];
}
int querymax2(int x,int y)
{
makeroot(x);access(y);splay(y);return mn2[y];
}
int main()
{
//freopen("1977.in","r",stdin);
//freopen("1977.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
sort(e+1,e+m+1,cmp);
for(int i=1;i<=n;i++) pa[i]=i;
int hm=0;
tot=n;
for(int i=1;i<=m;i++)
{
int fu=find(e[i].u),fv=find(e[i].v);
if(fu==fv) continue;
ans+=e[i].c;
//cout<<e[i].u<<' '<<e[i].v<<' '<<e[i].c<<endl;
hm++;pa[fu]=fv;
v[++tot]=e[i].c;link(e[i].u,tot);link(e[i].v,tot);
flag[i]=1;
if(hm==n-1) break;
}
for(int i=1;i<=m;i++)
{
if(flag[i]) continue;
int v=querymax(e[i].u,e[i].v);
//cout<<v<<' '<<e[i].c<<endl;
if(v==e[i].c) v=querymax2(e[i].u,e[i].v);
if(v>0) out=min(out,ans-v+e[i].c);
}
printf("%lld\n",out);
return 0;
}