数据结构1 倍增、ST表,RMQ
使用 倍增、ST表 解决区间最值的查询问题 RMQ
1.倍增
任意整数均可表示成若干个2的次幂项的和.
5--》101
26--》11010
也就是说2的次幂可以拼接成任何一个需要的值
倍增:成倍的增长,如果问题的状态空间特别大,一步一步的递推算法复杂度太高,可以通过倍增思想,只考察2的整数次幂位置,快速缩小求解范围,知道所要的解。
2.ST表
系数表Sparse Table算法采用倍增的思想,在O(NlogN)的时间构造一个二维表之后,可以在o(1)的时间在线查询区间[l,r]的最值。ST算法可以有效的解决在线RMQ问题
F[i,j]表示区间[i, i+2^j-1]的最值,区间长度为2^j
其实就是基于动态规划的思想 的 静态表方法
通过k=logn将🌲树表划分取值
1,2,3...k
1 #include <iostream> 2 #include <cmath> // 使log函数 3 /* 4 cmath使用方法介绍: 5 log():以e为底的对数,exp(5) = e^5 log(exp((5)) = 5 6 log10():以10为底的对数 7 log2():以2位底的对数 8 任何一个对数logm(n) = log(n)/log(,) 9 */ 10 using namespace std; 11 12 const int maxn = 105; 13 int n, a[maxn], F[maxn][maxn]; // F(i,j)表示区间[i, i+2^j-1]的最值,区间长度为2^j 14 15 void ST_create(){ 16 for(int i=1; i<=n; i++) // 初始化 17 F[i][0] = a[i]; //n-1 18 int k=log2(n); // log(n)/log(2) 两种版本的问题 19 for(int j=1; j<=k; j++){ 20 for(int i=1; i<=n-(1<<j)+1; i++){ // n-2^j+1:n-3、n-5、n-7 21 F[i][j] = max(F[i][j-1], F[i+(1<<(j-1))][j-1]); 22 } 23 } 24 } 25 26 int ST_query(int l, int r){ // 求区间[l,r]的最值 27 int k=log(r-l+1); 28 return max(F[l][k], F[r-(1<<k)+1][k]); 29 // 取两个区间最值 F[l][k]:l往后数k个 F[r-(1<<k)+1][k]:r往前数k个 30 } 31 32 void ST_print(){ 33 // 按列填写的表 34 int k=log2(n); 35 for(int j=0; j<=k; j++){ 36 for(int i=0; i<=n-(1<<j)+1; i++){ // n-2^j+1 打印第一列 37 cout << F[i][j] << " "; 38 } 39 cout << endl; 40 } 41 } 42 43 int main(){ 44 // 10 5 3 7 2 12 1 6 4 8 15 45 int l, r; 46 int i, v; 47 cin >> n; 48 for(i=1; i<=n; i++) 49 cin >> a[i]; 50 ST_create(); 51 ST_print(); 52 cout << "输入查询最值的区间l r:" << endl; 53 cin >> l >> r; 54 cout << ST_query(l, r) << endl; 55 return 0; 56 }
POJ3264
http://poj.org/problem?id=3264
6 3 1 7 3 4 2 5 1 5 4 6 2 2
1 #include <iostream> 2 #include <cstdio> 3 #include <cmath> 4 #include <algorithm> 5 6 using namespace std; 7 8 const int maxn = 50000+10; 9 10 int h[maxn]; 11 int Fmax[maxn][20]; 12 int Fmin[maxn][20]; 13 int N, Q; 14 15 void ST_create(){ 16 for(int i=1; i<=N; i++){ 17 Fmax[i][0] = Fmin[i][0] = h[i]; 18 } 19 int k = log2(N); 20 for(int j=1; j<=k; j++){ 21 for(int i=1; i<=N-(1<<j)+1; i++){ 22 Fmax[i][j] = max(Fmax[i][j-1], Fmax[i+(1<<(j-1))][j-1]); 23 Fmin[i][j] = min(Fmin[i][j-1], Fmin[i+(1<<(j-1))][j-1]); 24 } 25 } 26 } 27 28 int ST_query(int l, int r){ 29 int k = log2(r-l+1); 30 return max(Fmax[l][k], Fmax[r-(1<<k)+1][k]) - min(Fmin[l][k], Fmin[r-(1<<k)+1][k]); 31 32 } 33 34 int main(){ 35 // freopen("test.txt", "r", stdin); 36 // cin >> N >> Q; 37 // for(int i=1; i<=N; i++){ 38 // cin >> h[i]; 39 // } 40 // ST_create(); 41 // int l, r; 42 // for(int i=1; i<=Q; i++){ 43 // cin >> l >> r; 44 // cout << ST_query(l, r) << endl; 45 // } 46 int l, r; 47 while(~scanf("%d%d", &N, &Q)){ 48 for(int i=1; i<=N; i++) 49 scanf("%d", &h[i]); 50 ST_create(); 51 for(int i=1; i<=Q; i++){ 52 scanf("%d%d", &l, &r); 53 printf("%d\n", ST_query(l, r)); 54 } 55 } 56 return 0; 57 }
注意题目中测试用例可能会有多个