加载中...

st表

兴奋值

https://ac.nowcoder.com/acm/contest/37160/H

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>

using namespace std ;

using ll = long long ;

const int N = 2e5 + 100 ;

// 求max[l<=i<=r] { min(a_i,i - l + 1) }
// 发现 i - l + 1 在一次询问中是单调递增的
// 那么当我们确定答案mid,那么其实就变成查询[i + mid - 1,r]中max(a_i)
// 因为这时候小于i + mid - 1 的位置受到mid的限制,肯定不会大于mid,那么只有后面
// 通过 max(a_i) 是否大于mid就可以判断正确性了。
// 所以我们使用二分+st表

int n,m ;
int a[N] ;
int f[N][20] ;  // st表

void init(){  // 初始化st表
    for(int k = 0 ; k < 20 ; k ++){
        for(int i = 1  ; i + (1 << k) - 1 <= n ; i ++){
            if(!k) f[i][k] = a[i] ;
            else f[i][k] = max(f[i][k-1],f[i + (1 << (k - 1))][k-1]) ;
        }
    }
}

int get(int l,int r){  // st表获得区间最大值
    if(l > r) return 0 ;
    int len = r - l + 1;
    int k = log(len) / log(2) ;
    return max(f[l][k],f[r - (1 << k) + 1 ][k]) ;
}

bool check(int mid,int a,int b){  // 二分检查函数
    return get(a + mid - 1,b) >= mid ;
}

int calc(int a,int b){  // 进行二分
    int l = 0,r = b - a + 1 ;
    while(l < r){
        int mid = l + r + 1 >> 1 ;
        if(check(mid,a,b)) l = mid ;
        else r = mid - 1 ;
    }
    return l ;
}

int main(){
    scanf("%d%d",&n,&m) ;

    for(int i = 1 ; i <= n ; i ++) scanf("%d",&a[i]) ;

    init() ; // 初始化st表

    while(m --){
        int a,b ;
        scanf("%d%d",&a,&b) ;

        printf("%d ",calc(a,b)) ;
    }
    return 0 ;
}
posted @ 2022-07-21 18:32  liang302  阅读(40)  评论(0编辑  收藏  举报