(那一天我唯一徹底搞懂的東西然而現在也忘光光)
先看題:(RP++)
先跳過暴力,這一題肯定不行的
這時就需要ST表,ST表:Sparse Table Algorithm
ST表分為兩部分,
預處理和
查詢。
預處理:
采用DP的思想,
f[i][ j]
表示
[i , i+2^
j
- 1]
區間中的最小值(也就是從第i個數起連續2j個數中的最小值)。
數列3,2,4,5,6,8,1,2,9,7。f[1][0]=3,f[1][1]=2,f[1][2]=2,f[1][3]=1,f[2][0]=2,f[2][1]=2,f[2][2]=2……
f[i][ j]可以由f[i][j-1]和f[i+2^j-1][ j-1]導出:
f[i][ j-1]表示
區間[i , i+2^j-1-1]的最小值
f[i+2^
j-1
][ j-1]表示
區間[i+2^j-1 , i+2^j-1+2^j-1-1]=[i+2^j-1, i+2^j-1] 的最小值 ,所以有DP方程:
f[i][ j]=min(f[i][ j-1],f[i+2^
j-1
][ j-1])
這一部分都很好懂,接下來就是怎么查詢了。

關於長度2k解釋:因為要完全覆蓋整個區間,而對於求最大值和最小值兩個區間有交集是沒有影響的(不是精確覆蓋),所以可以求2k<=r-l+1
例題:(裸的ST表)
代碼:
#include<iostream> #include<cstdio> #include<cmath> using namespace std; int a[1000001]; int Fmax[100005][25]; int Fmin[100005][25]; int n,m; void MM() { for(int j=1;j<=floor(log(n)/log(2));j++) for(int i=1;i+(1<<j)-1<=n;i++) { Fmax[i][j]=max(Fmax[i][j-1],Fmax[i+(1<<(j-1))][j-1]); Fmin[i][j]=min(Fmin[i][j-1],Fmin[i+(1<<(j-1))][j-1]); } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); Fmax[i][0]=a[i]; Fmin[i][0]=a[i]; } MM(); int x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); int k=floor(log(y-x+1)/log(2)); printf("%d\n",max(Fmax[x][k],Fmax[y-(1<<k)+1][k])); } return 0; }
提供雙倍經驗(練手)
再看一道題?
大概思路:
(代碼有時間再放吧。。要月考了。。。)