1. 程式人生 > 其它 >天才的記憶(RMQ,ST表)

天才的記憶(RMQ,ST表)

原題連結

分析

裸的ST表

ST表

初始化

倍增枚舉出區間的最大值,f[N] [M]代表,從n開始長度為2^m的區間最值。

查詢

[l,r]

1.求出該區間長度最接近的倍增預處理後的長度,k = log(len)/log(2);

2.最大值為

\[Max=max(f[l][k],f[r-2^k+1][k]) \]

ACcode

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10,M = 18;
int f[N][M];
int w[N];
int n,m;
//初始化
void init()
{
    for(int j=0;j<18;j++)//列舉區間長度
        for(int i=1;i+(1<<j)-1<=n;i++)//列舉區間
        {
            if(!j) f[i][j]=w[i];//如果區間長度為1,則就是它本身
            else f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);//否則,則最大值為[i,i+2^(j-1)]和[i+2^(j-1),i+2^j]中的最大值
        }
}

int query(int l,int r)
{
    int len = r-l+1;
    int k = log(len)/log(2);//從區間開頭,得到的最長的預處理的區間
    return max(f[l][k],f[r-(1<<k)+1][k]);//這個區間的最大值,是[l,l+2^k],[r-2^k+1,r]中的最大值
}

int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    init();
    scanf("%d",&m);
    while (m -- ){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",query(l,r));
    }
    return 0;
}