最近公共祖先(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问题描述

最近公共祖先(LCA)问题优化模板(DFS+ST, 倍增法+链式前向星)_第1张图片
对于如上图所示的树,我们如果想知道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
#include
#include
#include
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<
 
 
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<
			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<
	//这里的意思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

你可能感兴趣的:(入门贴,数据结构,算法)