博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
次小生成树
阅读量:5356 次
发布时间:2019-06-15

本文共 2756 字,大约阅读时间需要 9 分钟。

次小生成树

次小生成树

我们已经熟知了求最小生成树的方法,用kruskal,prim算法都可以搞

那么我们如何求次小生成树呢?
这里次小生成树的定义是

边权和严格大于最小生成树的边权和最小的生成树

求解方法

次小生成树嘛,肯定和最小生成树脱不了关系

那么我们首先求出最小生成树

接下来,一个比较显然的思路是

枚举每一条未加入最小生成树的边,加入最小生成树,同时在最小生成树中删除边权最大的边
如果你想到了这里并写出了代码,那么恭喜你
你在里成功还有一步之遥成功掉进坑里了
比如下面的例子
%E6%AC%A1%E5%B0%8F%E7%94%9F%E6%88%90%E6%A0%91.png
蓝边表示最小生成树中的边,黄边表示新加入的边
在这种情况下,如果仅仅记录最大值的话,得到的答案一定是错的
所以我们还要记录严格小于最大值的最大值
当产生冲突的时候我们需要删除严格小于最大值的最大值

优化

但是这样效率太低了,每一次查询都是\(O(n)\)

有没有更好的方法呢?

不要忘了,最小生成树它是一棵树呀

树的链上最大最小值操作,你想到了什么?

没错!树上倍增

我们在倍增的过程中记录下最大值和严格小于最大值的最大值

这样每次查询的复杂度就变成\(log(n)\)

总结

流程

整个算法的流程大概是

  1. 求出最小生成树
  2. 构造出倍增数组
  3. 每次树上倍增查询

时间复杂度

用kruskal是\(O(m\log m+Q\log (n))\)

用prim是\(O(n\log n+Q\log (n))\)
Q为询问次数

代码

放一道

// luogu-judger-enable-o2#include
#include
#include
#include
#include
#define int long long using namespace std;const int MAXN=400001;const int INF=1e15+10;inline int read(){ char c=getchar();int x=0,f=1; while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();} return x*f;}struct Edge{ int u,v,w;}E[MAXN];int Enum=1;void Add(int x,int y,int z){ E[Enum].u=x; E[Enum].v=y; E[Enum].w=z;Enum++;}struct node{ int u,v,w,nxt;}edge[MAXN];int head[MAXN];int num=1;int N,M;int fa[MAXN],vis[MAXN],sum;int deep[MAXN],f[MAXN][21],maxx[MAXN][21],minx[MAXN][21];void AddEdge(int x,int y,int z){ edge[num].u=x; edge[num].v=y; edge[num].w=z; edge[num].nxt=head[x]; head[x]=num++;}int find(int x){ if(fa[x]==x) return fa[x]; else return fa[x]=find(fa[x]);}int unionn(int x,int y){ int fx=find(x),fy=find(y); fa[fx]=fy;}int comp(const Edge &a,const Edge &b){ return a.w
maxx[ f[j][i-1] ][i-1]) minx[j][i]=max(minx[j][i],maxx[ f[j][i-1] ][i-1]); else minx[j][i]=max(minx[j][i],maxx[j][i-1]); } }}int LCA(int x,int y){ if(deep[x]
=0;i--) if(deep[ f[x][i] ] >= deep[y] ) x=f[x][i]; if(x==y) return x; for(int i=18;i>=0;i--) if(f[x][i] != f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0];}int findmax(int x,int lca,int val){ int ans=0; for(int i=18;i>=0;i--) { if(deep[ f[x][i] ] >= deep[lca]) { if(maxx[x][i]==val) ans=max(ans,minx[x][i]); else ans=max(ans,maxx[x][i]); x=f[x][i]; } } return ans;}void work(){ int ans=INF; for(int i=1;i<=Enum-1;i++) { if(vis[i]) continue; int x=E[i].u,y=E[i].v,z=E[i].w; int lca=LCA(x,y); int lmx=findmax(x,lca,z); int rmx=findmax(y,lca,z); if(max(lmx,rmx)!=z) ans=min(ans,sum+z-max(lmx,rmx)); } printf("%lld",ans);}main(){ #ifdef WIN32 freopen("a.in","r",stdin); #else #endif N=read(),M=read(); memset(head,-1,sizeof(head)); for(int i=1;i<=N;i++) fa[i]=i; for(int i=1;i<=M;i++) { int x=read(),y=read(),z=read(); Add(x,y,z); } Kruskal(); deep[1]=1; dfs(1,0); pre(); work(); return 0; }

转载于:https://www.cnblogs.com/zwfymqz/p/8457550.html

你可能感兴趣的文章
基于百万数据集的登录存储过程
查看>>
使用windos模拟搭建web集群(二)
查看>>
Learning to Rank(转)
查看>>
MSSQL 行转列
查看>>
Office2010安装需要MSXML版本6.10.1129.0的方法
查看>>
leetcode个人题解——#33 Search in Rotated Sorted Array
查看>>
cocos-lua学习笔记(五)cocos2d-Lua类的实现
查看>>
cocos-lua学习笔记(六)一个简单的Button
查看>>
Node_初步了解(2)
查看>>
Vim使用总结
查看>>
Server-U设置虚拟路径映射网络共享文件夹
查看>>
大一统的宇宙与太极原理之随想
查看>>
启动Myeclipse报错“Failed to create the Java Virtual Machine”的解决办法
查看>>
NS记录
查看>>
自己动手从头制作WordPress主题(二)实现主题选项
查看>>
spring @Value示例
查看>>
dubbo2.5.6从下载到编译成功并且部署成功过程
查看>>
MyBatis学习总结——实现关联表查询(转)
查看>>
中庸----做人的智慧
查看>>
Webstorm编译TypeScript
查看>>