倍增和LCA
来源:互联网 发布:无锡亿美网络 编辑:程序博客网 时间:2024/06/18 06:54
倍增和LCA
现在终于可以写这篇文章了,拖了很久没有学的倍增在去NOIP2015打酱油之前终于初步学习完。再次特别声明十分感谢fye的帮助,生命中第一篇倍增和LCA就是以她的代码为模板的,并且应该会一直延续下去。。。= =
【倍增是什么】
顾名思义,倍增就是根据已经得到的信息,将考虑的范围扩大一倍,从而加速操作的一种思想。
【有关倍增的算法】
使用了倍增思想的算法有很多,包括归并排序、快速幂、基于ST表的RMQ算法和树上倍增找LCA等,还有FFT、后缀数组等高级算法(wok…),而我们只是初级入门,学习了树上倍增找LCA。
【树上倍增找LCA】
算法的基本思路是:求两个点的LCA,先把深度较深的点移到和另一个点相同的深度,然后一起向上移动,直到重合,就找到了LCA,倍增其实是加速区间操作的一种手段,因为相当于把每个数进行二进制分解,倍增的复杂度在logN级别。
在这里不做详细讲解,只给出普通查找和使用倍增优化的代码模板,详情可以百度“倍增算法 高天宇”,SLYZGTY学长为你详细讲解。= =
【普通查找LCA】
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>using namespace std;int n,a,b,x,y,ans;int h[105],f[105][105],fa[105];bool bb[105];void build(int t,int dep){ h[t]=dep; int r; for (r=1;r<=n;++r) if (f[t][r]&&!bb[r]){ bb[r]=true; fa[r]=t; build(r,dep+1); }}int lca(int x,int y){ if (h[x]<h[y]) swap(x,y); int k=h[x]-h[y]; for (int i=1;i<=k;++i) x=fa[x]; while (fa[x]!=fa[y]){ x=fa[x];y=fa[y]; } return fa[x];}int main(){ scanf("%d%d%d",&n,&a,&b); for (int i=1;i<n;++i){ scanf("%d%d",&x,&y); f[x][y]=f[y][x]=1; } bb[1]=true; build(1,1); ans=lca(a,b); printf("%d",ans); return 0;}
【倍增优化】
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#define sz 8using namespace std;int n,a,b,i,t,ans,x,y;int v[105],next[105],point[105],h[105],mi[sz],f[105][sz],root[105];inline void add(int x,int y,int i){ v[i]=y; next[i]=point[x]; point[x]=i;}inline void build(int x,int fa,int dep){ h[x]=dep; for (i=1;i<sz;++i){ if (h[x]-mi[i]<1) break; f[x][i]=f[f[x][i-1]][i-1]; } for (int i=point[x];i;i=next[i]) if (v[i]!=fa){ f[v[i]][0]=x; build(v[i],x,dep+1); } }inline int lca(int x,int y){ if (h[x]<h[y]) swap(x,y);int k=h[x]-h[y]; for (int i=0;i<sz;++i) if ((k>>i)&1) x=f[x][i]; if (x==y) return x; for (i=sz-1;i>=0;--i) if (f[x][i]!=f[y][i]){x=f[x][i];y=f[y][i];} return f[x][0];}int main(){ mi[0]=1; for (i=1;i<sz;++i) mi[i]=mi[i-1]*2; scanf("%d%d%d",&n,&a,&b); for (i=1;i<n;++i){ scanf("%d%d",&x,&y); add(x,y,i<<1); add(y,x,i<<1|1); } build(1,0,1); ans=lca(a,b); printf("%d",ans); return 0;}
其实上面两个程序的数据是很弱的,暴力查找LCA都可以承受,只是为了练练手。。。
使用倍增优化用到了next数组,因为如果使用倍增时数据很大,其他存储方式无法存储,next数组是优先考虑的存储形式。
f[x][i]表示结点x向上蹦2^i个点到达的结点是哪个,从小到大枚举i,转移方程为:f[x][i]=f[f[x-1][i-1]][i-1]。
如果在预处理时和查找LCA时记录一些别的信息,我们还可以处理很多维护和查询问题。
算法精妙,用心体会。。。
1 0
- 倍增和LCA
- lca倍增
- lca(倍增)
- 倍增LCA
- 倍增lca
- LCA倍增
- LCA(倍增)
- 倍增 LCA
- 【LCA】倍增法 LCA
- 最小生成树和倍增法求lca(Uva11354Bond)
- c++最近公共祖先LCA(倍增算法和tarjan)
- LCA倍增算法(模板)
- HDU 4547 倍增LCA
- 倍增lca模板
- LCA倍增法模板
- lca倍增dp
- 倍增LCA模板
- 倍增法求LCA
- Uva101—— The Blocks Problem
- H5之js拼接select级联优化
- iOS NSUserDefaults 之最简单存取数据 小Demo
- LightOJ 1005 - Rooks (排列组合)
- [c#][Windows Phone | Windows]FlipView循环滚动,图片轮播
- 倍增和LCA
- Java中的网络编程
- IOS开发-C基础2
- 线程相关
- Xcode开发中遇到的Bug
- ASP导出为Word或Excel的最简单方法
- Uva10474——Where is the Marble?
- Hough变换在直线提取中的改进
- oh my zsh