题解 P4180 【【模板】严格次小生成树[BJWC2010]】
其实这并不是一个模板题
一、题目
点此看题
二、解法
发现次小生成树和最小生成树只有一条边的差异,为什么呢?考虑每一条不在最小生成树上的边如果加上去的增量,发现它是非负的,要生成次小生成树,肯定要最小化增量,所以只替换一条边是最优的。
考虑每一条边去替换树上的边,先加入这条边,会与树形成一个环,发现环上的最大边就是我们替换的树边,但由于题目要求严格次小,就不能取和加入边权值相等的树边,暴力跑即可。
考虑对暴力优化,发现找最大边的过程本质就是一个
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int MAXN = 100005;
const int inf = (1ll<<62);
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,tot,ans=inf,f[MAXN],p[MAXN],dep[MAXN];
int fa[MAXN][20],Max[MAXN][20],sub[MAXN][20];
long long mst;
struct edge
{
int v,c,next;
}e[2*MAXN];
struct node
{
int u,v,c;
bool operator < (const node &x) const
{
return c<x.c;
}
}a[3*MAXN];
int op(int a,int b,int lim)
{
if(a>=lim) return b>=lim?0:b;
if(b>=lim) return a>=lim?0:a;
return max(a,b);
}
int findSet(int x)
{
if(x^p[x]) p[x]=findSet(p[x]);
return p[x];
}
void MST()
{
sort(a+1,a+1+m);
for(int i=1;i<=n;i++)
p[i]=i;
for(int i=1;i<=m;i++)
{
int u=a[i].u,v=a[i].v,c=a[i].c,x=findSet(u),y=findSet(v);
if(x==y) continue;
e[++tot]=edge{v,c,f[u]},f[u]=tot;
e[++tot]=edge{u,c,f[v]},f[v]=tot;
mst+=c;
p[x]=y;
}
}
void dfs(int u,int par)
{
fa[u][0]=par;
dep[u]=dep[par]+1;
for(int i=1;i<20;i++)
{
int pos=fa[u][i-1];
Max[u][i]=max(Max[u][i-1],Max[pos][i-1]);
sub[u][i]=max(sub[u][i-1],sub[pos][i-1]);
fa[u][i]=fa[pos][i-1];
if(Max[u][i-1]^Max[pos][i-1])
sub[u][i]=max(sub[u][i],min(Max[u][i-1],Max[pos][i-1]));
}
for(int i=f[u];i;i=e[i].next)
if(e[i].v^par)
{
Max[e[i].v][0]=e[i].c;
sub[e[i].v][0]=-inf;
dfs(e[i].v,u);
}
}
void updata(int &x,int u,int i,int lim)
{
x=op(x,Max[u][i],lim);
x=op(x,sub[u][i],lim);
}
int lca(int u,int v,int lim)
{
int res=-inf;
for(int i=19;i>=0;i--)
{
if(dep[fa[u][i]]>=dep[v]) updata(res,u,i,lim),u=fa[u][i];
if(dep[fa[v][i]]>=dep[u]) updata(res,v,i,lim),v=fa[v][i];
}
if(u==v) return res;
for(int i=19;i>=0;i--)
if(fa[u][i]^fa[v][i])
{
updata(res,u,i,lim);updata(res,v,i,lim);
u=fa[u][i],v=fa[v][i];
}
updata(res,u,0,lim);updata(res,v,0,lim);
return res;
}
signed main()
{
n=read();m=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read();
a[i]=node{u,v,c};
}
MST();
dfs(1,0);
for(int i=1;i<=m;i++)
{
int val=lca(a[i].u,a[i].v,a[i].c);
if(val!=-inf) ans=min(ans,a[i].c-val);
}
printf("%lld\n",ans+mst);
}
tips
1、
2、注意要开
3、极大值用