学习笔记(倍增)Balanced Lineup G题解

倍增(RMQ):用于计算区间极值
使一步一步增加转变为2^k步增加。举个例子:
一只兔子从1跳到10,一步一步跳要10步,倍增的思想是:
先跳8步,没到,跳到9.
跳4步,过头了,不跳.
跳2步,过头了,不跳.
跳1步,到了,跳到10.
时间复杂度是从O(n)到O(log2n);
洛谷例题Balanced Lineup G
这是一道求区间内最大值和最小值的题。典型倍增题。
我们用f[i][j]记录以i为起点,长度为2^j的区间内的最小值,f[i][0]就是当前位置的点。我们用式子f[i][j]=max(f[i][j-1],f[i+(1<<(j-1)][j-1])来计算。
我们将f[i][j]以i为起点,长度为2^ j的区间分成两部分求,是以i为起点,长度为2^ (j-1)的区间最大值与以i+(1<<(j-1)为起点,长度为2^ (j-1)的区间最大值中的较大值。之后再分解到每个点,就可得到最大值。
如图分别求黄色区间和红色区间最大值
在这里插入图片描述

最小值g[i][j]同上。
这里的k我随便取到个最大值到20,只要2^k能超过题目的数据范围就行
代码

#include<bits/stdc++.h>
using namespace std;
const int N=50010;
int n,q,h[N],f[N][21],g[N][21];
int main(){
cin>>n>>q;
for(int i=1;i<=n;i++)
cin>>h[i],f[i][0]=h[i],g[i][0]=h[i];
for(int j=1;j<=20;j++){
 for(int i=1;i+(1<<j)-1<=n;i++){
  f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
  g[i][j]=min(g[i][j-1],g[i+(1<<(j-1))][j-1]);
 }
} 
while(q--){
 int l,r,x,y;
 cin>>l>>r;
 int k=log2(r-l+1);
 x=max(f[l][k],f[r-(1<<k)+1][k]);
 y=min(g[l][k],g[r-(1<<k)+1][k]);
 printf("%d\n",x-y);
}
}

猜你喜欢

转载自blog.csdn.net/Nefeertari/article/details/107630554