【洛谷P4180】严格次小生成树
题目大意:给定一个 N 个顶点,M 条边的带权无向图,求该无向图的一个严格次小生成树。
引理:有至少一个严格次小生成树,和最小生成树之间只有一条边的差异。
题解:
通过引理可以想到一个暴力,即:先求出最小生成树,并记录树边,再枚举删除 MST 中的每一条边,每次重新做一次最小生成树算法,并将计算出来的所有结果取最小值即为答案。以 Kruskal 算法为例,暴力的时间复杂度为 \(O(n^2logn)\)。
现在可以考虑在已知最小生成树的基础上,枚举每条非树边,将该边加入最小生成树中,并删去加入边的两个端点之间的任意一条边即可。由于要求次小生成树,显然删去的边权要尽可能大,又由于要求严格次小,为了避免非树边权值和端点路径上最大边权相同,需要记录一下端点路径上的严格次大边权。由此,问题转化成了如何求解一棵树上任意两点之间的最大边权和严格次大边权。直接考虑倍增即可。时间复杂度为 \(O(nlogn)\)。
代码如下
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
const int maxn=1e5+10;
const int maxe=3e5+10;
typedef pair<long long,long long> P;
inline int read(){
int x=0,f=1;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch));
do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch));
return f*x;
}
struct rec{
int from,to;
long long w;
}edge[maxe];
bool cmp(const rec &a,const rec &b){return a.w<b.w;}
struct node{
int nxt,to;
long long w;
}e[maxn<<1];
int tot=1,head[maxn];
inline void add_edge(int from,int to,long long w){
e[++tot]=node{head[from],to,w},head[from]=tot;
}
int n,m,fa[maxn],f[maxn][21],dep[maxn];
long long mx1[maxn][21],mx2[maxn][21],ans,mst;
bool used[maxe];
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void kruskal(){
sort(edge+1,edge+m+1,cmp);
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1,sum=n;i<=m;i++){
if(sum==1)break;
int x=find(edge[i].from),y=find(edge[i].to);
if(x!=y){
used[i]=1,mst+=edge[i].w,fa[x]=y,--sum;
add_edge(edge[i].from,edge[i].to,edge[i].w);
add_edge(edge[i].to,edge[i].from,edge[i].w);
}
}
}
inline void upd(long long &max1,long long &max2,long long x,long long y){
if(max1==x)max2=max(max2,y);
else if(max1<x)max2=max1,max1=x,max2=max(max2,y);
else max2=max(max2,x);
}
void dfs(int u,int fa){
for(int i=1;i<=20;i++){
f[u][i]=f[f[u][i-1]][i-1];
mx1[u][i]=mx1[u][i-1],mx2[u][i]=mx2[u][i-1];
upd(mx1[u][i],mx2[u][i],mx1[f[u][i-1]][i-1],mx2[f[u][i-1]][i-1]);
}
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;if(v==fa)continue;
dep[v]=dep[u]+1,f[v][0]=u,mx1[v][0]=e[i].w;
dfs(v,u);
}
}
P lca(int x,int y){
long long max1=0,max2=0;
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[f[x][i]]>=dep[y]){
upd(max1,max2,mx1[x][i],mx2[x][i]);
x=f[x][i];
}
if(x==y)return mp(max1,max2);
for(int i=20;i>=0;i--)
if(f[x][i]!=f[y][i]){
upd(max1,max2,mx1[x][i],mx2[x][i]);
upd(max1,max2,mx1[y][i],mx2[y][i]);
x=f[x][i],y=f[y][i];
}
upd(max1,max2,mx1[x][0],mx2[x][0]);
upd(max1,max2,mx1[y][0],mx2[y][0]);
return mp(max1,max2);
}
void read_and_parse(){
n=read(),m=read();
for(int i=1;i<=m;i++)edge[i].from=read(),edge[i].to=read(),edge[i].w=read();
kruskal();
dfs(1,0);
}
void solve(){
ans=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=m;i++)if(!used[i]){
P tmp=lca(edge[i].from,edge[i].to);
if(edge[i].w==tmp.first&&tmp.second)ans=min(ans,edge[i].w-tmp.second);
else if(edge[i].w>tmp.first)ans=min(ans,edge[i].w-tmp.first);
}
printf("%lld\n",mst+ans);
}
int main(){
read_and_parse();
solve();
return 0;
}
【洛谷P4180】严格次小生成树的更多相关文章
- 洛谷P4180 [BJWC2010]次小生成树(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
- bzoj 1977 洛谷P4180 严格次小生成树
Description: 给定一张N个节点M条边的无向图,求该图的严格次小生成树.设最小生成树边权之和为sum,那么严格次小生成树就是边权之和大于sum的最小的一个 Input: 第一行包含两个整数N ...
- BZOJ1977或洛谷4180 [BJWC2010]次小生成树
一道LCA+生成树 BZOJ原题链接 洛谷原题链接 细节挺多,我调了半天..累炸.. 回到正题,我们先求出随便一棵最小生成树(设边权和为\(s\)),然后扫描剩下所有边,设扫到的边的两端点为\(x,y ...
- 洛咕P4180 严格次小生成树
鸽了很久的一道题(?)貌似是去年NOIP前听的emm... 首先我们分析一下最小生成树的性质 我们kruskal建树的时候呢是从小到大贪心加的边,这个的证明用到拟阵.(我太菜了不会) 首先我们不存在连 ...
- 洛谷 P 4180 次小生成树
题目描述 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得 ...
- 洛谷.4180.[模板]次小生成树Tree(Kruskal LCA 倍增)
题目链接 构建完MST后,枚举非树边(u,v,w),在树上u->v的路径中找一条权值最大的边(权为maxn),替换掉它 这样在 w=maxn 时显然不能满足严格次小.但是这个w可以替换掉树上严格 ...
- 【题解】洛谷P4180 [BJWC2010] 严格次小生成树(最小生成树+倍增求LCA)
洛谷P4180:https://www.luogu.org/problemnew/show/P4180 前言 这可以说是本蒟蒻打过最长的代码了 思路 先求出此图中的最小生成树 权值为tot 我们称这棵 ...
- 洛谷P4180【Beijing2010组队】次小生成树Tree
题目描述: 小C最近学了很多最小生成树的算法,Prim算法.Kurskal算法.消圈算法等等.正当小C洋洋得意之时,小P又来泼小C冷水了.小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还 ...
- 洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)
洛谷题目传送门 %%%TPLY巨佬和ysner巨佬%%% 他们的题解 思路分析 具体思路都在各位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 大多数算法都要用kruskal把最小 ...
随机推荐
- Session会话与Cookie简单说明
会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话.常用的会话跟踪技术是Cookie与Session.Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端 ...
- ELK实时日志分析平台环境部署--完整记录
在日常运维工作中,对于系统和业务日志的处理尤为重要.今天,在这里分享一下自己部署的ELK(+Redis)-开源实时日志分析平台的记录过程(仅依据本人的实际操作为例说明,如有误述,敬请指出)~ ==== ...
- E. Train Hard, Win Easy
链接 [http://codeforces.com/contest/1043/problem/E] 题意 有n个人,每个人都有做出a,b题的分数,xi,yi,但是有些人是不能组队的,问你每个人和其他能 ...
- 《Linux内核设计与实现》读书笔记 5
第五章系统调用 5.1与内核通信 系统调用在用户空间进程和硬件设备间添加了一个中间层, 作用:为用户空间提供了一种硬件的抽象接口:保证了系统的稳定和安全,避免应用程序不正确使用硬件,窃取其他进程的资源 ...
- 网易云课堂-----Linux内核分析-----期末主观题
姚歌 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 下面是对8个课题的 ...
- 2017-2018-2 1723《程序设计与数据结构》第十一周作业 & 实验三 & (总体)第三周结对编程 总结
作业地址 第十一次作业:https://edu.cnblogs.com/campus/besti/CS-IMIS-1723/homework/1933 (作业界面已评分,可随时查看,如果对自己的评分有 ...
- idea使用优化
一.idea设置目录说明 1.bin目录包含我们的启动文件.虚拟机配置信息和idea属性信息等 2.help目录:帮助文档 3.jre64 : idea自带的jre环境 4.lib:idea所依赖的类 ...
- Hibernate的初次使用
使用hibernate的四个步骤:第一:创建一个hibernate.cfg.xml.<!DOCTYPE hibernate-configuration PUBLIC "-//Hiber ...
- 发布阶段 github和360移动助手及总结
经过一系列的冲刺和加工 最激动人心的无非在发布平台上公布上自己辛苦奋斗了一个周期的产品,这个时候的我们就像Iphone 6发布会上得CEO,为自己的产品完美画上了研发的句号. 接下来的日子就是准备ve ...
- MySQL 单表优化
一.表字段优化 1.整数类型尽量使用 TINYINT.SMALLINT.MEDIUM_INT 而不是INT,非负数要加上UNSIGNED 2.VARCHAR的长度分配要合理,不要过大 3.时间字段不超 ...