次小生成树(学习笔记)

news/2025/3/22 8:54:52/文章来源:https://www.cnblogs.com/XichenOC/p/18786226

P4180 BJWC2010 严格次小生成树 - 洛谷

简介:

如同字面意思。次小生成树就是严格只比最小生成树大一点的生成树。数学公式来表达就是:

若最小生成树选出的边集为 \(E_M\),严格次小生成树的边集为 \(E_S\),若 \(value(e)\) 表示边 \(e\) 的权值。那就有

\[\sum_{e_\in E_M}value(e)<\sum_{e_\in E_S}value(e) \]

思路:

先考虑最小生成树的 \(kruskal\) 算法。该算法是将图上的所有边给从小到大排序,在用并查集来判断该边是否是树边。最后找到 \(n-1\) 条边即是最小生成树了。而次小生成树也就只与最小生成树上有一个边的关系。证明很简单:若需要替换多条边,那这些边替换后必须保证树的连通。那也就要保证每个边替换后都要联通。既然要严格次小,与其说选择多条边替换为更大值,不如将一条边给替换掉即可。

那我们就要考虑替换那一条边。要替换的边肯定是在 \(kruskal\) 中没有选择到的边。那我们就可以枚举每一条没选到的边,然后在到树上选择适当的边来替换即可。首先先要确定那些边是可以替换的。我们发现若要保证替换后的边可以保证树连通。那只能替换改变所连接的两个节点所对应的路径。因为不能让新图成为一个环,就一定要断开一个,且若断开其他无关的边,那就会有无关的节点被孤立,使树无法联通。至于要替换哪一条,很明显是最大的边,这样就能使插值尽可能小。

实现:

若暴力枚举每一条边,在暴力枚举路径上的边,那复杂度就是 \(O(n^2)\) 。我们考虑求树上两点的路径时一般都会用到 \(lca\) 也就是最近公共祖先。而实现 \(lca\) 的方式有两种。一个是 倍增,另一个是树剖。可以发现。倍增就如同 \(st\) 表。既让如此,我们就可以在倍增求 \(lca\) 时顺便维护一下最大值。若用树剖的话,也可以用线段树来维护最大值。这样最后枚举所有边,在将答案取最小值即可。

注意:

1.若两个点间路径的最大值与要替换的边一样怎么办。因为这样替换后权值和不会发生变化。这样就需要在储存路径的次大值,若没有最大值,也就要返回 \(inf\)

2.由于存在自环,所以当遍历到自环边的时候,由于路径不存在边,那自然返回的为零。对于这种情况,只需特判一下自环跳过即可。

完整代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=3e5+10;
const int inf=0x3f3f3f3f3f3f3f3f;
struct node{int nxt,to,val;
}e[N]; 
int h[N],cnt;
void add(int u,int v,int w) {e[++cnt].nxt=h[u];e[cnt].to=v; e[cnt].val=w;h[u]=cnt;
}
struct edge{int u,v,w;bool used;bool operator<(const edge &x)const{return w<x.w;}
}g[N];
int fa[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);
}
int n,m;
int ans0;
int vis[N];
void kurskal(){for(int i=1;i<=n;i++)fa[i]=i;sort(g+1,g+m+1);for(int i=1;i<=m;i++){int u=g[i].u,v=g[i].v,w=g[i].w;int fu=find(u),fv=find(v);if(fu==fv)continue;ans0+=w;fa[fu]=fv;add(u,v,w);add(v,u,w);g[i].used=true;}
}
int f[N][20],mx[N][20],smx[N][20],dep[N];
void dfs(int u){dep[u]=dep[f[u][0]]+1;for(int i=1;i<=18;i++){f[u][i]=f[f[u][i-1]][i-1];mx[u][i]=max(mx[u][i-1],mx[f[u][i-1]][i-1]);if(mx[u][i-1]==mx[f[u][i-1]][i-1]){smx[u][i]=max(smx[u][i-1],smx[f[u][i-1]][i-1]);}else{smx[u][i]=min(mx[u][i-1], mx[f[u][i-1]][i-1]);}}for(int i=h[u];i;i=e[i].nxt) {int v=e[i].to,w=e[i].val;if (v==f[u][0])continue;f[v][0]=u; mx[v][0]=w; dfs(v);}
}
int lca(int u,int v){if(dep[u]<dep[v])swap(u,v);for(int i=18;i>=0;i--){if(dep[f[u][i]]>=dep[v]){u=f[u][i];}}if(u==v)return u;for(int i=18;i>=0;i--){if(f[u][i]!=f[v][i]){u=f[u][i];v=f[v][i];}}return f[u][0];
}int calc(int u,int v,int w){int l=lca(u,v);int max1=0,max2=0; for(int i=18;i>=0;i--){if(dep[f[u][i]]>=dep[l]){if(max1==mx[u][i])max2=max(smx[u][i],max2);if(max1>mx[u][i])max2=max(mx[u][i],max2);if(max1<mx[u][i]){max2=max(max1,smx[u][i]);max1=mx[u][i];}u=f[u][i];}if(dep[f[v][i]]>=dep[l]){if(max1==mx[v][i]) max2=max(smx[v][i],max2);if(max1>mx[v][i]) max2=max(mx[v][i],max2);if(max1<mx[v][i]){max2=max(max1,smx[v][i]);max1=mx[v][i];}v=f[v][i];}}if(w!=max1)return ans0-max1+w;if(max2)return ans0-max2+w;return inf;
}
signed main(){scanf("%lld%lld",&n,&m);for(int i=1;i<=m;i++){scanf("%lld%lld%lld",&g[i].u,&g[i].v,&g[i].w);}kurskal();dfs(1);int ans=inf;for(int i=1;i<=m;i++){if(g[i].used || g[i].u==g[i].v)continue;ans=min(ans,calc(g[i].u,g[i].v,g[i].w));}printf("%lld\n",ans);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/903364.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

deepseek模型部署到本地使用+投喂数据训练

近期,由于国外大量攻击,导致 DeepSeek 经常无法使用;另外,许多朋友希望在本地搭建自己的知识库,以保护自己的资料不被外泄。因此,越来越多的人希望能够在本地部署 DeepSeek,但对于技术难度有所担忧。别担心,这篇教程将为你扫清所有障碍!从环境搭建到模型运行,每一步都…

Axure RP上使用 Font Awesome 图标库

Axure RP 可以使用 Web Fonts,这让置入 Font Awesome 变得非常方便。Font Awesome 是一种字体,只是主要针对图标使用,而非我们所熟知的中文/西文字体。 进行简单的几步设置,就可以在自己项目上面使用 Font Awesome 的 1609 个免费图标。图标覆盖广泛,风格也相对统一。 一、…

读DAMA数据管理知识体系指南27文件和内容管理概念(上)

读DAMA数据管理知识体系指南27文件和内容管理概念(上)1. 文件和内容管理 1.1. 文件和内容管理是指针对存储在关系型数据库之外的数据和信息的采集、存储、访问和使用过程的管理 1.2. 重点在于保持文件和其他非结构化或半结构化信息的完整性,并使这些信息能够被访问 2. 业务驱…

(Windows11)如何自编译Aseprite(像素画软件) - 1.3.12版本

如何自编译Aseprite(像素画软件)-windows-以1.3.12版本为例 1. Aseprite说明开源像素画软件,自带调色板 Steam也可购买:steam购买2. 官方编译说明(Windows系统下) 官方库提供了win、mac以及Linux编译方式 文档地址:https://github.com/aseprite/aseprite/blob/main/INSTAL…

BUAA_OO_Unit1总结

Unit1 总结 1. 程序结构分析 1.1 代码结构(类图)1.2 类的度量统计类名 属性个数 方法个数 方法名 方法规模(代码行) 控制分支数目 类总代码规模(行)Function 4 6 Function 5 0 85sort 10 1 (双重循环)getCan 20 3 (条件+循环嵌套)huanCan 15 2 (条件替换逻辑)prework 15 …

永久免费!支持视频号下载,2025最新版本

在昨天的推文中给大家分享了一款非常不错的 Ai 工具,含有 Ai 一键抠图、Ai 无损放大等功能,对于设计和作图的小伙伴来说,非常的有帮助这款Ai 合集工具,内容丰富,且使用简单,纯在线使用,不消耗本地电脑硬件内存,有需要的小伙伴可以点击下方链接体验 一键Ai抠图、无损放大…

AbstractAutoProxyCreator#postProcessBeforeInstantiation

一、定义 postProcessBeforeInstantiation 是 Spring AOP 动态代理的核心扩展点,通过提前创建代理对象优化性能,并支持丰富的自定义逻辑(如事务、安全) 二、代码分析 public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws Be…

Day20_javascanner_struct

Java JavaDoc javadoc命令是用来生成自己API文档的 参数信息: @author 作者名 @version 版本号 @since 指明需要最早使用的jdk版本 @param 参数名 @return 返回值情况 @throws 异常抛出情况 /*** @author XXX* @version 1.0* @since 1.8*/public class Doc {String name;/*** …

k8s基本字段

k8s基本字段 limits字段 此字段限制的是硬件的资源,如果容器尝试申请超过限制的内存将会终止容器 requests字段 此字段限制的是容器可以请求的资源,可以超出request申请额外的资源,但是不能超过limits, 500m等于0.5个CPU本地临时性文件,采用这种配置时,你会把所有类型的临…

【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(3)

比赛链接 本文发布于博客园,会跟随补题进度实时更新,若您在其他平台阅读到此文,请前往博客园获取更好的阅读体验。 跳转链接:https://www.cnblogs.com/TianTianChaoFangDe/p/18786128 开题 + 补题情况 很菜的一把,就开了三个签到题,1001 Lucas 定理花了好久才看出来,明明…

51单片机学习笔记-3

串口通信UART(universal asynchronous receiver transmitter,通用异步收发器):可用来实现串口通信。串口硬件:基础串口包含TXD/RXD两个通信线,他们交叉连接。(如DB9通常使用2(RXD),3(TXD),5(GND)。) 当串口两头电平标准不一样时,需要叫电平转换芯片。TTL电平:5V表示1,…