【数据结构】ST表
ST表
ST表基于倍增的思想,可以做到的离线预处理和
的在线查询。它可以用于解决满足结合律的可重复贡献问题。
可重复贡献问题 是指对于运算
,满足
,则对应的区间询问就是一个可重复贡献问题。例如,最大值有
,gcd 有
,所以 RMQ 和区间 GCD 就是一个可重复贡献问题。像区间和就不具有这个性质,如果求区间和的时候采用的预处理区间重叠了,则会导致重叠部分被计算两次,这是我们所不愿意看到的。另外, opt还必须满足结合律才能使用 ST 表求解。
具体实现如下:
令表示区间
的最大值(或其他意义)。
显然。
我们将表示的区间划分为两部分,分别是
和
,在离散意义下,两个区间刚好可以覆盖原有区间,因此有状态转移方程:
。
接下来对于查询区间中的最大值,我们将查询区间分为
和
,令
,得
,此时可证明两区间可以覆盖原区间(不保证交集为空)。
即
模板
#include <bits/stdc++.h>
using namespace std;
inline int read(){
int x = 0,f = 1;
char c = getchar();
while (!isdigit(c)){
if (c == '-')
f = -1;
c = getchar();
}
while (isdigit(c)){
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int N = 1e5 + 5;
int f[N][20];
int n,m;
int main(){
ios::sync_with_stdio(false),cin.tie(0);
n = read(),m = read();
for (int i = 1;i <= n;++i){
f[i][0] = read();
}
for (int i = 1;i <= __lg(N);++i){
for (int j = 1;j + (1 << i) - 1 <= n;++j){
f[j][i] = max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
}
//puts("YES");
while (m--){
int l,r;
l = read(),r = read();
int s = __lg(r-l+1);
printf("%d\n",max(f[l][s],f[r-(1<<s)+1][s]));
}
return 0;
} 统计区间gcd
const int N = 1e4 + 5;
int f[N][20];
int n,m;
int main(){
ios::sync_with_stdio(false),cin.tie(0);
cin >> n >> m;
for (int i = 1;i <= n;++i){
cin >> f[i][0];
}
for (int i = 1;i <= __lg(N);++i){
for (int j = 1;j + (1 << i) - 1 <= n;++j){
f[j][i] = __gcd(f[j][i-1],f[j+(1<<(i-1))][i-1]);
}
}
while (m--){
int l,r;
cin >> l >> r;
int s = __lg(r-l+1);
printf("%d\n",__gcd(f[l][s],f[r-(1<<s)+1][s]));
}
return 0;
} 