一、ST表
提供一种求取区间最值的新手段(对与重复贡献问题是一种很棒的方法)
基于倍增的手段,取2 的 i 次方
作为区间的长度并进行预处理
要素:
- 注意保证区间长度,那么那么区间的左界只能放弃
- 倍增的底数是2
- 快速取log在数据很大时候是很重要的
int f[i][j]; 存放了从闭区间[i,i + 2^j - 1]的最值
int log[x] 快速取得log 2 x 的值,借由预处理达到
手段:将要求最值的区间转换成两个更小的区间,由传统意义上的 i --- j
转换为跨度为2 ^ j
的数组,大幅压维
操作1 预处理:
log2 的值应该迅速以O(1)查出
void pre()
{
for(int i=1;i<=n;i++)f[i][0]=a[m]; 长度为1 仅有自己,那么最值就是自己
logn[1]=0;
logn[2]=1;
for(int i=1;i<=n;i++)logn[i]=logn[i/2]+1; 数学性方法
}
操作2 处理数据:
借由倍增思想,把大区间缩小一半取两个分区间的最大值
void st()
{
for(int j=1;j<=21;j++) 最外层枚举2 的指数
for(int i=1;i+(1<<j)-1<=n;i++) 区间区间左界不能大于待处理数据量
{
f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); 大区间取一半裂为两个小区间
}
}
操作3 查询最值:
int find(int x,int y)
{
if(x>y)swap(x,y);
int ans;
int p=log[y-x+1]; 区间长度变为2的指数形式
ans=max(f[x][p],f[y-(1<<p)+1][p]);
return ans;
}