2017-08-26 21:44:45
writer:pprp
RMQ问题就是区间最大最小值查询问题;
这个SparseTable算法构造一个表,F[i][j] 表示 区间[i, i + 2 ^ j -1]的最大或者最小值
ST分为两个部分
1、nlogn的预处理
预处理主要用到了动态规划,二分区间每个区间长度为 2 ^ (j -1)找到一个递推关系;
F[i][j] = min(F[i][j - 1],F[i + (1 << (j - 1))][j - 1]);
2、查询部分更为巧O(1)得到询问结果
对于任意一个区间【n,m】来说,可以将其划分为两个以上区间的和
【m,n】 = 【m, m+2^k-1】 + 【n-2^k-1,n】
其中k = log2(n-m+1)
实现的代码如下:
/*
@theme:ST表(sparse table)稀疏表
@writer:pprp
@declare:用动态规划的思想来解决RMQ问题;
@date:2017/8/26
*/
/*方程
F[i,j]:区间[i,i + 2^j - 1]的最小值,此时区间长度为2^j
转移方程:F[i,j] = min(F[i,j - 1],F[i + 2^(j - 1),j - 1])
初始化:F[i,0] = nArr[i];
*/
#include <bits/stdc++.h>
using namespace std;
int F[1000000][20];//待比较元素的个数最大为1百万
void SparseTable(int a[], int len)
{
//初始化
for(int i = 0 ; i < len ; i++)
F[i][0] = a[i];
//递推
//找到j的范围log2(n)
int nlog = int(log(double(len))/log(2.0));
for(int j = 1 ; j <= nlog; j++)
{
for(int i = 0 ; i < len ; i++)
{
//区间右端点不能超过数组最后一位下标
if((i + (1 << j) -1) < len )
{
F[i][j] = min(F[i][j - 1],F[i + (1 << (j - 1))][j - 1]);
}
}
}
}
int RMQ(int a[], int len, int Start, int End)
{
//中间变量的选取log2(len)
int nlog = (int)(log(double(End-Start+1))/log(2.0));
return min(F[Start][nlog], F[End - (1 << nlog) + 1][nlog]);
}
int main()
{
int a[] = {2,34,2,3,23,2,23,1,23,123,23,232,3,25,565,76};
for(int i = 0 ; i < 16 ; i++)
{
cout << a[i] <<" ";
}
cout << endl;
SparseTable(a,16);
int l, r;
while(cin >> l >> r)
{
cout << RMQ(a,16,l,r) << endl;
}
return 0;
}
ST模板
#include <bits/stdc++.h> using namespace std; int F[1000000][20]; void ST(int a[],int len) { for(int i = 0 ; i < len ; i++) F[i][0] = a[i]; int nlog = int(log(double(len))/log(2.0)); for(int j = 1; j <= nlog; j++) { for(int i = 0 ; i < len ; i++) { if(i+(1<<j)-1 < len) F[i][j] = max(F[i][j-1],F[i+(1<<(j-1))][j-1]); } } } int RMQ(int a[],int len, int l, int r) { int nlog = floor(log(double(r-l+1))/log(2.0)); return max((F[l][nlog]),F[r-(1<<nlog)+1][nlog]); } int main() { int a[10000]; int n; cin >> n; for(int i = 0 ; i < n ; i++) cin >> a[i]; ST(a,n); int l,r; int cas; cin >> cas; while(cas--) { cin >> l >> r; cout << RMQ(a,n,l,r) << endl; } return 0; }