ST表
思想
O(nlogn)的预处理,O(1)的查询
倍增。令f[i] [j]为以i为左端点,长度为2 ^ j区间的最大值/最小值,则f[i] [j] = max(f[i] [j-1], f[i + (1 << (j-1) )] [j-1])。
查询时,比如要查区间[L,R]的最大值,对应L + 2^j - 1 == R,所以j = log2(R - L + 1)
但是区间长度并不一定正好满足R - L + 1 == 2的整数幂,那就左右端点都求,分为[L,L + 2^j - 1]和[R - 2^j + 1,R],中间重合了一部分区域[R - 2^j + 1,L + 2^j - 1],因为求RMQ,所以可行
代码
#include<bits/stdc++.h>
using namespace std;
int n, m, f[110000][30];
int main(){
cin >> n >> m;
for(int i = 1;i <= n;i ++)
cin >> f[i][0];//f[i][j] : [i, i + 2^j - 1]的最大值
for(int j = 1;j <= 20;j ++){
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]);
}
while(m --){
int l, r;
cin >> l >> r;
//l + 2 ^ j - 1 = r,这里左端点是l
//所以j = log2(r + 1 - l)
int j = log2(r + 1 - l);
cout << max(f[l][j], f[r - (1 << j) + 1][j])) << endl;
//左:l + 2^j - 1 ->[l, l + 2^j - 1]
//右:r - 2^j + 1 + 2^j - 1 = r ->[r - 2^j + 1, r]
}
return 0;
}
这篇博客介绍了如何利用线段树(Segment Tree)进行区间最大值/最小值的预处理和O(1)查询。通过O(nlogn)的时间复杂度建立线段树,并展示了一个查询区间[L, R]最大值的实例,利用位运算和动态规划优化查询效率。
2万+

被折叠的 条评论
为什么被折叠?



