1. 程式人生 > >ST表——模板(luogu3865)

ST表——模板(luogu3865)

ima 個數 col set style 數字 -m || 技術

題目背景

這是一道ST表經典題——靜態區間最大值

請註意最大數據時限只有0.8s,數據強度不低,請務必保證你的每次查詢復雜度為 O(1)

題目描述

給定一個長度為 N 的數列,和 M 次詢問,求出每一次詢問的區間內數字的最大值。

輸入輸出格式

輸入格式:

第一行包含兩個整數 N, M ,分別表示數列的長度和詢問的個數。

第二行包含 N 個整數(記為 ai),依次表示數列的第 i 項。

接下來 M 行,每行包含兩個整數 li, ri,表示查詢的區間為 [ li, ri ]

輸出格式:

輸出包含 M 行,每行一個整數,依次表示每一次詢問的結果。

輸入輸出樣例

輸入樣例
8 8
9 3 1 7 5 6 0 8
1 6
1 5
2 7
2 6
1 8
4 8
3 7
1 8
輸出樣例
9
9
7
7
9
8
7
9

講解:

作用——O(nlogn)預處理,O(1) 求區間最大值

思想——倍增

設一個Max[ i ][ j ] 表示從 i 位置 ,長度2j 的區間最大值

以樣例為例

9 3 1 7 5 6 0 8

Max[1][1]=9
Max[2][1]=3
Max[3][1]=7
Max[4][1]=7
Max[5][1]=6
Max[6][1]=6
Max[7][1]=8
Max[1][2]=9
Max[2][2]=7
Max[3][2]=7
Max[4][2]=7
Max[5][2]=8
Max[1][3]=9

查詢(如圖)

技術分享圖片


算出 k=log2() ,等同於:

for(k=0;(1<<k)<=r-l+1;k++) ;
k--;

就好啦,很簡單吧~個鬼

std代碼

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=1e6+10;
int read()
{
    char c=getchar();int x=0,f=1;
    while(c<0||c>9){if(c==-)f=-1;c=getchar();}
    while(c>=0&&c<=9){x=x*10+c-0;c=getchar();}
    
return x*f; } int Max[MAXN][21]; int Query(int l,int r) { int k=log2(r-l+1); return max(Max[l][k],Max[r-(1<<k)+1][k]); } int main() { int N=read(),M=read(); for(int i=1;i<=N;i++) Max[i][0]=read(); for(int j=1;j<=21;j++) for(int i=1;i+(1<<j)-1<=N;i++) { Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]); // printf("Max[%d][%d]=%d\n",i,j,Max[i][j]); } for(int i=1;i<=M;i++) { int l=read(),r=read(); printf("%d\n",Query(l,r)); } return 0; }

ST表——模板(luogu3865)