前言
首先需要了解什么是最小生成树,还要知道什么是倍增(求Lca).
上面的东西如果了解了,就可以开始进入学习的路途了!!
1 算法框架
1.1 整体思路
用不是最小生成树上的边去更新答案.
1.2 具体维护
对于每一个倍增跳上去的,要维护两个东西:
- 路径的边权最大值.
- 路径的边权次大值
2 具体实现
我们考虑一下对于每一条边(不在最小生成树上),如果要把它加入答案,如何更新?
MST-路径最大值+边权.
然后这个东西就可以很愉快地解决了...
其实不是的,如果题目求的是次小生成树,这题就没了,但是题目要求的是严格次小生成树,怎么办呢?
考虑一下,如果要这样子,我们更新答案就不能和MST相等,然后依旧可以很愉快地解决了!!!
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
using namespace std;
#define int long long
const int N=100010,M=300010,Inf=2e18+10;
struct node{
int u,v,w;
}e[M];
int fa[N],front[N],to[N<<1],nxt[N<<1],w[N<<1],MST,cnt,n,m,k,flag[M];
int f[N][20],Min[N][20],Max[N][20],dep[N];
int find(int x){
if(fa[x]!=x)fa[x]=find(fa[x]);
return fa[x];
}
void Add(int u,int v,int W){
to[++cnt]=v;nxt[cnt]=front[u];w[cnt]=W;
front[u]=cnt;
}
bool cmp(node a,node b){
return a.w<b.w;
}
void dfs(int u,int Fa){
f[u][0]=Fa;
for(int i=front[u];i;i=nxt[i]){
int v=to[i];
if(v!=Fa){
dep[v]=dep[u]+1ll;
Max[v][0]=w[i];
Min[v][0]=-Inf;
dfs(v,u);
}
}
}
int LCA(int u,int v){
if(dep[u]<dep[v])swap(u,v);
for(int i=18;~i;i--)
if(dep[f[u][i]]>=dep[v])
u=f[u][i];
if(u==v)return u;
for(int i=18;~i;i--)
if(f[u][i]!=f[v][i])
u=f[u][i],v=f[v][i];
return f[u][0];
}
int qmax(int u,int v,int W){
int ans=-Inf;
for(int i=18;~i;i--)
if(dep[f[u][i]]>=dep[v]){
if(W!=Max[u][i])ans=max(ans,Max[u][i]);
else ans=max(ans,Min[u][i]);
u=f[u][i];
}
return ans;
}
signed main(){
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int u,v,W;scanf("%lld%lld%lld",&u,&v,&W);
e[i]=(node){u,v,W};
}
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++){
int u=find(e[i].u),v=find(e[i].v);
if(u!=v){
flag[i]=1;
Add(e[i].u,e[i].v,e[i].w);
Add(e[i].v,e[i].u,e[i].w);
fa[v]=u;MST+=e[i].w;
k++;if(k==n-1)break;
}
}
Min[1][0]=-Inf;
dep[1]=1;
dfs(1,-1);
for(int j=1;j<=18;j++)
for(int i=1;i<=n;i++){
f[i][j]=f[f[i][j-1]][j-1];
Max[i][j]=max(Max[i][j-1],Max[f[i][j-1]][j-1]);
Min[i][j]=max(Min[i][j-1],Min[f[i][j-1]][j-1]);
if(Max[i][j-1]>Max[f[i][j-1]][j-1])
Min[i][j]=max(Min[i][j],Max[f[i][j-1]][j-1]);
else if(Max[i][j-1]<Max[f[i][j-1]][j-1])
Min[i][j]=max(Min[i][j],Max[i][j-1]);
}
int ans=Inf;
for(int i=1;i<=m;i++)
if(!flag[i]){
int u=e[i].u,v=e[i].v;
int lca=LCA(u,v);
int Maxu=qmax(u,lca,e[i].w),Maxv=qmax(v,lca,e[i].w);
ans=min(ans,MST-max(Maxu,Maxv)+e[i].w);
}
printf("%lld\n",ans);
return 0;
}
原文地址:https://www.cnblogs.com/biscuit46/p/9880303.html
时间: 2024-11-08 15:14:01