luogu P3865 【模板】ST表

luogu P3865 【模板】ST表

利用递推解决区间最值问题

建成后,不支持修改区间上某一点的值

建表O(nlogn),查询O(1)

1<< t == 二的 t 次方

p[ k ][ i ]==从 i 开始包括 i 长为 2^k 的区间的最值

p[ 0 ][ i ]即为 a[ i ]的值本身

1.建表时

    区间[ i , i + 2^k -1 ] 最值等于区间[ i , i +2( k-1 )-1 ]与区间 [ i +2( k -1) ][ i + 2^k -1]的最值

p[k][i]=max(p[k-1][i],p[k-1][i+(1<<(k-1))])

    最开始知道所有的 p[ 0 ][ i ],用 p[ 0 ][ i ]去推 p[ 1 ][ i ]直到到 p[ t ][ i ]

2.询问时

    区间[ l ,r ]最值等于区间[ l , l +2^k -1]与区间[ r -2^k +1 , r ]的最值

    由于k 取log2( r - l +1)向下取整,p[ k ][ l ]与p[ t ][ r – (1 << t) + 1]取最值返回

    2^(k+1)一定能包含整个区间[ l ,r ],所以这两个 P 数组所代表的区间,一定会覆盖所求区间,且不会越界

#include<cstdio>
#include<cmath>      //log2()函数需调用<cmath>
#include<iostream>   //max,min,swap调用<iostream>
using namespace std;
int n,m;
int p[50][100001],a[100001];
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) p[0][i]=a[i];
    int t=log2(n);
    for(int k=1;k<=t;k++)   //建表
        for(int i=1;i+(1<<k)-1<=n;i++)
            p[k][i]=max(p[k-1][i],p[k-1][i+(1<<(k-1))]);int l,r;
    for(int i=1;i<=m;i++)   //询问
    {
        scanf("%d%d",&l,&r);
        t=log2(r-l+1);
        printf("%d
",max(p[t][l],p[t][r-(1<<t)+1]));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/QAQq/p/10301856.html