最近公共祖先(LCA)问题优化模板(DFS+ST, 倍增法+链式前向星)

文章介绍的很多,很啰嗦,可以根据目录跳转文章目录1.LCA问题描述2.一个效率不是很高的算法(DFS + ST)2.1 ST算法介绍2.2 DFS+ST算法概述2.3 C++代码3.倍增法+链式前向星3.1 链式前向星3.2 倍增法3.3 算法步骤和举例3.4 C++模板参考1.LCA问题描述对于如上图所示的树,我们如果想知道F节点和E节点的最近公共祖先,也就B,我们应该怎么办呢?这就...
摘要由CSDN通过智能技术生成

文章介绍的很多,很啰嗦,可以根据目录跳转

1.LCA问题描述

在这里插入图片描述
对于如上图所示的树,我们如果想知道F节点和E节点的最近公共祖先,也就B,我们应该怎么办呢?这就是LCA问题。

2.一个效率不是很高的算法(DFS + ST)

DFS算法:深度优先搜索
ST算法:Sparse Table

2.1 ST算法介绍

DFS很熟悉就不多介绍了,ST算法是解决区间最值问题(RMQ)提出来的一个算法。对于区间[l,r]求区间内的最值。
算法是通过维护一个ST表f[][],利用倍增的想法,例如对于f[i][j]表示从i位开始的2^j个数中的最值。可以在O(nlogn)的时间处理问题,每次查询花费O(1)时间。
算法流程:

/*
题目:洛谷3865 ST表
给定一个长度为 N 的数列,和 M 次询问,求出每一次询问的区间内数字的最大值。
*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;

int n,m; //n个数,m次查询
int a[maxn]; // 区间
int f[maxn][20];//ST表, f[i][j]表示从i位起的2^j个数中的最大数,即[i,i+(1<<j)-1] 
 
 
void ST_prewoek() // 预处理
{
   
	for(int i=1;i<=n;i++) f[i][0]=a[i]; // 目标区间为自身,最值就是自身
	for(int i=1,imax=log2(n);i<=imax;i++)//目标区间大小,最大不会超过log2(n)
		for(int j=1;j+(1<<i)-1<=n;j++)//注意j的右端点为j+(1<<i)-1,-1是因为要包含j自己 
			f[j][i]=max(f[j][i-1],f[j+(1<<i-1)][i-1]);//对于f[j][i],最值为[j,j+1<<(i-1)]和[j + 1<<(i-1),1<<(i-1)]的最值相比较
}
 
 
int ST_query(int l,int r)//求[l,r]中的最大值 
{
   
	int k=log2(r-l+1);//区间长度r-l+1 
	return max(f[l][k],f[r-(1<<k)+1][k]);//第1个区间:[l,l+(1<<k)-1];第2个区间:[r - (1<<k) + 1,r]
	//这里的意思l-r不一定是2的幂,其中包含的最大的为2^k。那么区间就分为了[l, l + 2^k-1]以及[r-2^k+1, 2^k]。
	//中间可能有重叠部分为[r-2^k+1, l + 2^k-1]
}
 
 
int main()
{
   
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	ST_prewoek();
	while(m--)
	{
   
		int l,r,ans;
		scanf("%d%d",&l,&r);
		ans=ST_query(l,r);
		printf("%d\n",ans
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值