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; }