0 面向问题
我们希望有一个数据结构能够解决静态区间求最值、gcd....等问题并且可以在 \(O(nlogn)\) 范围内预处理 \(O(1)\) 查询
1 思路
ST表通常维护一些具有可合并性的东西,就是可以分别计算并且不在乎重复计算,比如最大最小值和最大公约数
(但是区间和之类就不行)
以最大值为例
考虑倍增
我们设一个数组 \(F_{i,j}\) 表示从 \(i\) 开始(包括 \(i\))的 \(2^j\) 个数的最大值,即 \([i,i+2^j-1]\) 范围的 \(\max\)
这个东西跟 dp
很像,我们可以看看这玩意怎么转移
注意力稍微集中一下我们很快可以发现 \(F_{i,j}=\max(F_{i,j-1},F_{i+2^{j-1},j-1})\)
边界也十分简单 \(F_{i,0}=a_i\) 其中 \(a\) 是原数组
我们可以码一个简单地预处理:
const int N=1e5,LGN=31;//数组长度和logn的上界
#define tn(x) (1<<(x));
//简单地宏定义一下 2^x 这个函数方便用
void init(){
LOG[1]=0,LOG[2]=1;
for(int i=3;i<=n;i++)LOG[i]=LOG[i/2]+1;
//此处为预处理log2(n) 的值
for(int i=1;i<=n;i++) cin>>a[i];
for(int j=0;j<=LGN;j++){
for(int i=1;i+tn(j)-1<=n;i++){
ST[i][j]=max(ST[i][j-1],ST[i+tn(j-1)][j-1]);
}
}
}
这里多预处理了一下 \(log2\) 因为后边要用
查询呢?
现在稍微推一下,若查询区间为 \([l,r]\)
我们希望用两个区间,一个从 \(l\) 开始,一个在 \(r\) 结束,并且两个区间能覆盖到 \([l,r]\) 之间的每一个值
假如第一个区间是 \(F_{l,p}\),那么 \(p\) 一定是满足 \(l+2^p-1<=r\) 的最大的数
可求得 \(p=log2(r-l+1)\),不妨取另一个区间为 \(F_{r-2^p+1,p}\),因为 \(p\) 的最大性容易看出这两个区间的确可以覆盖 \([l,r]\)
code:
void qmax(int l,int r){
int p=LOG(r-l+1);
return max(ST[l][p],ST[r-tn(p)+1][p]);
}
标签:int,max,ST,数组,区间,预处理
From: https://www.cnblogs.com/exut/p/18187574