文章介绍的很多,很啰嗦,可以根据目录跳转
文章目录
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