1. 程式人生 > >【模板】st表

【模板】st表

st表 序列 spl line col ++ hide 處理 表示

利用了倍增的思想,st[i][j]表示[i, i + 2j - 1]的區間內的最(大、小)值

自然st[i][0]存的就是序列中的第i個數,區間[l, r]的長度為log2(r - l + 1)

預處理:

處理每個為2的倍數的區間:

區間 [i, i + 2j] 的值為區間 [i, i + 2j - 1] 和區間 [i + 2j - 1, i + 2j] 的最值

復雜度O(n log2 n)

關於每次取log2,用cmath裏的函數會很慢(保留了小數)

所以可以預處理出log2(i)的整數值

技術分享圖片
for(int i = 0; (1 << i) <= n; i++)
    Log2[
1 << i] = i; for(int i = 1; i <= n; i++) if(!Log2[i]) Log2[i] = Log2[i - 1];
處理log2

查詢[l, r]區間的最值:

取區間[l, l + 2k - 1]和區間[r - 2k + 1, r]的最值

復雜度O(1)

其實蠻好理解的...QwQ

【代碼:】

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 using namespace std;
 5 
 6 const
int MAXN = 1e5 + 1, MAXM = 1e6 + 1; 7 const int K = 18; 8 9 int n, m; 10 int a[MAXN], st[MAXN][K], Log2[MAXN]; 11 12 int Query(int l, int r) { 13 int x = Log2[r - l + 1]; 14 return max(st[l][x], st[r - (1 << x) + 1][x]); 15 } 16 int main() { 17 scanf("%d%d", &n, &m); 18
for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 19 for(int i = 1; i <= n; i++) st[i][0] = a[i]; 20 for(int j = 1; j <= K; j++) { 21 for(int i = 1; i + (1 << j) - 1 <= n; i++) 22 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 23 } 24 for(int i = 0; (1 << i) <= n; i++) 25 Log2[1 << i] = i; 26 for(int i = 1; i <= n; i++) 27 if(!Log2[i]) Log2[i] = Log2[i - 1]; 28 while(m--) { 29 int l, r; 30 scanf("%d%d", &l, &r); 31 printf("%d\n", Query(l, r)); 32 } 33 }

【模板】st表