已更新(2/3):st表、树状数组
st表、树状数组与线段树是三种比较高级的数据结构,大多数操作时间复杂度为O(log n),用来处理一些RMQ问题或类似的数列区间处理问题。
一、ST表(Sparse Table)
st表预处理时间复杂度O(n log n),查询O(1),但不支持在线更改,否则要重新进行预处理。
使用一个二维数组:st[i][j]存储i为起点,长度为2j的一段区间最值,即arr[i, i + 2j - 1]。
具体步骤(以最小值为例):
- 将st[i][0]赋值为arr[i];
- 利用动态规划思想,dp出st[i][j] = min(st[i][j - 1], st[i + 2j - 1][j - 1]) (1 ≤ i ≤ n, 1 ≤ j ≤ log2 n);
- 查询时,定义len为log2(r - l + 1),区间[l, r]的最小值为min(st[l][len],st[r - 2len + 1][len])。
总时间复杂度为O(n log n + q),q为请求数。
代码实现(两个st表分别求最大最小值):
#include <bits/stdc++.h> using namespace std; int stmin[60010][20], stmax[60010][20]; int n, q, arr[60010], minans, maxans; void init(){ for(int j = 1 ; j <= n ; j++)stmax[j][0]=stmin[j][0]=arr[j]; for(int i = 1 ; i <= log2(n) ; i++){ for(int j = 1 ; j <= n ; j++){ stmax[j][i] = stmax[j][i-1]; if(j + (1 << (i-1)) <= n ) stmax[j][i] = max(stmax[j][i], stmax[j+(1<<(i-1))][i-1]); stmin[j][i] = stmin[j][i-1]; if(j + (1 << (i-1)) <= n ) stmin[j][i] = min(stmin[j][i], stmin[j+(1<<(i-1))][i-1]); } } } void query(int l,int r){ int len = log2(r - l + 1); minans = min(stmin[l][len],stmin[r - (1 << len) + 1][len]); maxans = max(stmax[l][len],stmax[r - (1 << len) + 1][len]); } int main(){ scanf("%d %d", &n, &q); for(int i = 1 ; i <= n ; i++) scanf("%d", &arr[i]); init(); int l,r; for(int i = 1 ; i <= q ; i++ ){ scanf("%d %d", &l, &r); query(l, r); printf("%d %d\n", minans, maxans); } return 0; }