ST表
ST表是一種解決RMQ(區間最值問題)的強有力的工具
它可以做到O(nlogn)預處理,O(1)查詢最值。
實現
ST表其實是一種倍增的思想,我們就拿取最大值為例:
開一個二維數組Max,其中Max[i][j]表示從第i位開始,包括第i位在內的2^j個數中最大的數,例如Max[i][1]表示第i個數和第i+1個數中大的那個數。
然后就類似於二分的樣子,下一層也是拿兩個已得到的區間的最大值作比較,然后存儲。
預處理代碼
1 for(int j=1;j<=21;j++) 2 { 3 for(int i=1;i+(1<<j)-1<=n;i++) 4 { 5 Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]); 6 } 7 }
為什么要先循環j呢?因為我們是一層一層向上搜的,每一層的答案需要下面的基礎,所以把j放在外層,然后(1<<(j-1))就是把二進制的1向左移動(j-1)位,也就是2^(j-1)。
查詢
查詢也比較簡單,我們只需要求出k=log2(r-l+1)(求2的k次冪小於這一段區間的值,並且盡可能大),然后得到兩個區間,比較就行了
然后取最大值返回就可以了
1 int ST(int l,int r) 2 { 3 int k=log2(r-l+1); 4 return max(Max[l][k],Max[r-(1<<k)+1][k]); 5 }
既然了解了這么多,不如.......(放心,都是模板題)
洛谷P3865 【模板】ST表
1 #include<bits/stdc++.h> 2 #define N 100005 3 using namespace std; 4 int n,m; 5 int Max[N][21]; 6 int ST(int l,int r) 7 { 8 int k=log2(r-l+1); 9 return max(Max[l][k],Max[r-(1<<k)+1][k]); 10 } 11 int main() 12 { 13 cin>>n>>m; 14 for(int i=1;i<=n;i++) 15 { 16 scanf("%d",&Max[i][0]); 17 } 18 for(int j=1;j<=21;j++) 19 { 20 for(int i=1;i+(1<<j)-1<=n;i++) 21 { 22 Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]); 23 } 24 } 25 int l,r; 26 for(int i=1;i<=m;i++) 27 { 28 scanf("%d%d",&l,&r); 29 printf("%d\n",ST(l,r)); 30 } 31 return 0; 32 }
洛谷P2251 質量檢測
1 // luogu-judger-enable-o2 2 #include<bits/stdc++.h> 3 #define N 100005 4 using namespace std; 5 int n,m; 6 int Min[N][21]; 7 int ST(int l,int r) 8 { 9 int k=log2(r-l+1); 10 return min(Min[l][k],Min[r-(1<<k)+1][k]); 11 } 12 int main() 13 { 14 cin>>n>>m; 15 for(int i=1;i<=n;i++) 16 { 17 scanf("%d",&Min[i][0]); 18 } 19 for(int j=1;j<=21;j++) 20 { 21 for(int i=1;i+(1<<j)-1<=n;i++) 22 { 23 Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]); 24 } 25 } 26 for(int i=1;i+m-1<=n;i++) 27 { 28 printf("%d\n",ST(i,i+m-1)); 29 } 30 return 0; 31 }
洛谷P1816 忠誠
1 #include<bits/stdc++.h> 2 using namespace std; 3 int Min[100005][21]; 4 int n,m; 5 int ST(int l,int r) 6 { 7 int k=log2(r-l+1); 8 return min(Min[l][k],Min[r-(1<<k)+1][k]); 9 } 10 int main() 11 { 12 cin>>n>>m; 13 for(int i=1;i<=n;i++) 14 { 15 scanf("%d",&Min[i][0]); 16 } 17 for(int j=1;j<=21;j++) 18 { 19 for(int i=1;i+(1<<j)-1<=n;i++) 20 { 21 Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]); 22 } 23 } 24 for(int i=1;i<=m;i++) 25 { 26 int l,r; 27 scanf("%d%d",&l,&r); 28 printf("%d ",ST(l,r)); 29 } 30 }