【模板】严格次小生成树
作者:互联网
是无意间脑残点开的一道题目。。。呜。。。
(1e4+7写不起紫题系列)
\(LCA+Kruscal\)。先求一遍\(mst\),再遍历不在最小生成树里的每一条边。加入生成树&删除原树一条边。
删除的边::原树上这两点的路径上的最大边。必须计算这条边上(严格的!)次大值,如果最大值和加入的边权值相等就换为次大边。
然后找出最小策略。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define MAXN 300000
#define inf 0x7fffffff
using namespace std;
int n,m,cnt=0,tot=0;
struct data
{
int x,y,val;
bool book;
}a[MAXN];
struct edge
{
int next,to,v;
}e[MAXN<<1];
int amn=inf;
long long ans=0;
int f[MAXN],head[MAXN],deep[MAXN],fa[MAXN][17],adp[MAXN][17],bdp[MAXN][17];
bool cmp(data x,data y)
{
return x.val<y.val;
}
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].next=head[u];
e[cnt].v=w;
head[u]=cnt;
}
int find(int x)
{
if (f[x]==x) return x;
return f[x]=find(f[x]);
}
void dfs(int x,int ft)
{
for (int i=1;i<=16;i++)
{
if (deep[x]<(1<<i))
{
break;
}
fa[x][i]=fa[fa[x][i-1]][i-1];
adp[x][i]=max(adp[x][i-1],adp[fa[x][i-1]][i-1]);
if (adp[x][i-1]==adp[fa[x][i-1]][i-1])
{
bdp[x][i]=max(bdp[x][i-1],bdp[fa[x][i-1]][i-1]);
}
else
{
bdp[x][i]=min(adp[x][i-1],adp[fa[x][i-1]][i-1]);
bdp[x][i]=max(bdp[x][i],bdp[x][i-1]);
bdp[x][i]=max(bdp[x][i],bdp[fa[x][i-1]][i-1]);
}
}
for (int i=head[x];i;i=e[i].next)
{
if (e[i].to!=ft)
{
fa[e[i].to][0]=x;
adp[e[i].to][0]=e[i].v;
deep[e[i].to]=deep[x]+1;
dfs(e[i].to,x);
}
}
}
int dep;
int LCA(int x,int y)
{
if (deep[x]<deep[y])
{
swap(x,y);
}
dep=deep[x]-deep[y];
for (int i=0;i<=16;i++)
{
if ((1<<i)&dep)
{
x=fa[x][i];
}
}
for (int i=16;i>=0;i--)
{
if (fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
if (x==y) return x;
return fa[x][0];
}
void lca(int x,int ft,int c)
{
int maxa,maxb;
maxa=maxb=0;
dep=deep[x]-deep[ft];
for (int i=0;i<=16;i++)
{
if (dep&(1<<i))
{
if (adp[x][i]>maxa)
{
maxb=maxa;
maxa=adp[x][i];
}
maxb=max(maxb,bdp[x][i]);
x=fa[x][i];
}
}
if (maxa!=c)
{
amn=min(amn,c-maxa);
}
else
{
amn=min(amn,c-maxb);
}
}
int x,y,ftr;
void func(int ww,int uu)
{
x=a[ww].x;
y=a[ww].y;
ftr=LCA(x,y);
lca(x,ftr,uu);
lca(y,ftr,uu);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
f[i]=i;
}
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].val);
}
sort(a+1,a+m+1,cmp);
for (int i=1,xx,yy;i<=m;i++)
{
xx=find(a[i].x); yy=find(a[i].y);
if (xx!=yy)
{
f[xx]=yy;
ans+=a[i].val;
a[i].book=true;
add(a[i].x,a[i].y,a[i].val);
add(a[i].y,a[i].x,a[i].val);
tot++;
if (tot==n-1)
{
break;
}
}
}
dfs(1,0);
for (int i=1;i<=m;i++)
{
if (!a[i].book)
{
func(i,a[i].val);
}
}
printf("%lld",ans+amn);
return 0;
}
标签:include,fa,int,amn,生成,严格,maxb,maxa,模板 来源: https://www.cnblogs.com/Kan-kiz/p/10720259.html