一道复杂一点的倍增题,需要记录路径的最大值和第二大值。
注意,严格次小生成树,等生成树性质要明确
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
inline ll read()
{
ll ans,f=1;char ch;
while ((ch=getchar())<'0'||ch>'9') if (ch=='-') f=-1;ans=ch-'0';
while ((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-'0';
return ans*f;
}
int n,m,fa[120005];
struct aa
{
int u,v;
ll dis;
bool o;
bool operator <(const aa &b)const
{
return dis<b.dis;
}
}bian[320005];
int find(int i) { return fa[i]==i?i:fa[i]=find(fa[i]);}
int head[120005],tot;
struct aaa
{
int to,pre;
ll dis;
}edge[230005];
void addedge(int u,int v,ll dis)
{
edge[++tot].to=v;edge[tot].pre=head[u];edge[tot].dis=dis;head[u]=tot;
}
int f[120005][20],dep[120005];ll g1[120005][20],g2[120005][20];
ll se(ll a,ll b,ll c,ll d)
{
int j;ll t[4]={a,b,c,d};
sort(t,t+4);
for (j=3;j>=0;j--) if (t[j]!=t[3]) break;
if (j==-1) return 0;
return t[j];
}
void dfs(int u,int depth)
{
dep[u]=depth;
for (int i=1;i<=18;i++)
{
int ff=f[u][i-1];
f[u][i]=f[ff][i-1];
g1[u][i]=max(g1[u][i-1],g1[ff][i-1]);
g2[u][i]=se(g1[u][i-1],g1[ff][i-1],g2[u][i-1],g2[ff][i-1]);
}
for (int i=head[u];i;i=edge[i].pre)
if (dep[edge[i].to]==0)
{
int v=edge[i].to;
f[v][0]=u,g1[v][0]=edge[i].dis,g2[v][0]=0;
dfs(v,depth+1);
}
}
void updata(ll &fi,ll &se,ll a)
{
if (a>fi) se=fi,fi=a;
else if (a==fi) return;
else if (a>se) se=a;
}
void up(int &u,ll &fi,ll &se,int step)
{
for (int i=0;i<=18;i++)
if (step&(1<<i))
{
updata(fi,se,g1[u][i]);updata(fi,se,g2[u][i]);
u=f[u][i];
}
}
ll lca(int u,int v,ll dis)
{
ll se=0,fi=0;
if (dep[u]>dep[v]) up(u,fi,se,dep[u]-dep[v]);
else up(v,fi,se,dep[v]-dep[u]);
for (int i=18;i>=0;i--)
if (f[u][i]!=f[v][i])
{
updata(fi,se,g1[u][i]);updata(fi,se,g1[v][i]);
updata(fi,se,g2[u][i]);updata(fi,se,g2[v][i]);
u=f[u][i],v=f[v][i];
}
if (u!=v) updata(fi,se,g1[u][0]),updata(fi,se,g1[v][0]);
if (dis>fi) return fi;else return se;
}
int main()
{
n=read(),m=read();
int x,y;ll z;
for (int i=1;i<=m;i++) bian[i].u=read(),bian[i].v=read(),bian[i].dis=read();
sort(bian+1,bian+m+1);
for (int i=1;i<=n;i++) fa[i]=i;
ll sum=0,ans=1e16;
for (int i=1;i<=m;i++)
{
int fu=find(bian[i].u),fv=find(bian[i].v);
if (fu!=fv)
{
fa[fu]=fv;
sum+=bian[i].dis;
bian[i].o=true;
addedge(bian[i].u,bian[i].v,bian[i].dis);
addedge(bian[i].v,bian[i].u,bian[i].dis);
}
}
dfs(1,1);
for (int i=1;i<=m;i++)
if (!bian[i].o)
{
ll mx=lca(bian[i].u,bian[i].v,bian[i].dis);
if (mx!=0) ans=min(sum-mx+bian[i].dis,ans);
}
printf("%lld",ans);
return 0;
}