倍增学习以及最近公共祖先 LCA

本文介绍了树上倍增算法的基本原理和应用,用于优化在树结构中查找最近公共祖先(LCA)的问题。通过线性倍增预处理,可以在O(logn)时间内找到两点的LCA,同时探讨了LCA在路径转化和距离计算中的作用。
摘要由CSDN通过智能技术生成

倍增学习

基本原理

  • 对于一个n长的道路,若一步一步的跳,复杂度过高
  • 如何优化跳的方式???
  • 存在一些数1,2,4,8,16,32…
  • 对于任意数 x 都能被这些数所组合,且最多取一个
  • 因为如果取两个4,为啥不直接取一个8
  • 倍增处理:对于道路上的每个点,求出各点跳到其右边 1 , 2 , 4 , 8 , 16 , 2 k 1,2,4,8,16,2^k 1,2,4,8,16,2k 的内容,可用 f [ i ] [ j ] f[i][j] f[i][j] 表示第 i 个点所距离 2 j 2^j 2j 的点
  • 预处理方式:常有的有树上倍增和线性倍增

线性倍增

ST的原理就是基于线性倍增

树上倍增求LCA

  • lca定义:树上两个点的最近公共祖先
  • 暴力方法:让两个点不停的往上跳,直到调到他们的 l c a lca lca
  • 倍增原理:一步跳多格,快速跳到他们的 l c a lca lca

上核心代码及注释

void dfs(int u,int fa) {
	dep[u]=dep[fa]+1;
	f[u][0]=fa;
	for(int i=1; i<=20; i++)f[u][i]=f[f[u][i-1]][i-1]; //树上倍增预处理 nlogn
	for(int i=vex[u]; i; i=e[i].next) {
		int v=e[i].v;
		if(v==fa)continue;
		dfs(v,u);
	}
}
int lca(int x,int y) {
	if(dep[x]<dep[y])swap(x,y);
	for(int i=20; i>=0; i--) {
		if(dep[f[x][i]]<dep[y])continue;
		x=f[x][i];
		//深的先跳,直到跳到与浅的深度一致 
	}
	if(x==y)return y;//如果相同则 y就为 lca 
	for(int i=20; i>=0; i--) {
		if(f[x][i]==f[y][i])continue;
		x=f[x][i];
		y=f[y][i];
		//若不同,则二者一起跳,直到跳到二者均为 lca的儿子节点 
	}
	return f[x][0];
}

最近公共祖先

用途

  • 1.对于树上的一条路径 ( x , y ) (x,y) (x,y),其等价于 ( x , l c a ) + ( l c a , a ) − l c a (x,lca)+(lca,a)-lca (x,lca)+(lca,a)lca
  • 2.对于树上的一条路径 ( x , y ) (x,y) (x,y),其还可以等价于 ( r o o t , x ) + ( r o o t , y ) − ( r o o t , l c a ) − ( r o o t , f a [ l c a ] ) (root,x)+(root,y)-(root,lca)-(root,fa[lca]) (root,x)+(root,y)(root,lca)(root,fa[lca])
  • 转化之后可以利用差分,前缀和等思路将位置转化简单。
  • 例如:求两个点的距离 d i s = d e p [ x ] + d e p [ y ] − 2 × d e p [ l c a ] dis=dep[x]+dep[y]-2\times dep[lca] dis=dep[x]+dep[y]2×dep[lca]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值