#include<bits/stdc++.h> using namespace std; const int MAXN = 100005; const int LOGN = 20; int a[MAXN]; int st[MAXN][LOGN]; int n; void preprocess() { for(int i = 0; i < n; i++) st[i][0] = a[i]; for(int j = 1; (1 << j) <= n; j++) { for(int i = 0; i + (1 << j) - 1 < n; i++) { st[i][j] = min(st[i][j-1], st[i + (1 << (j-1))][j-1]); } } } int query(int l, int r) { int len = r - l + 1; int k = log2(len); return min(st[l][k], st[r - (1 << k) + 1][k]); } int main() { cin >> n; for(int i = 0; i < n; i++) cin >> a[i]; preprocess(); int q; cin >> q; while(q--) { int l, r; cin >> l >> r; cout << query(l, r) << endl; } return 0; }
在这个模板中,preprocess函数用于预处理ST表,query函数用于查询区间最小值。在main函数中,首先读入序列长度和序列元素,然后调用preprocess函数进行预处理,然后读入查询次数,对于每次查询,读入查询区间,然后调用query函数进行查询,并输出结果。
query函数中获取最值原理:
在query函数中,我们要查询的是区间[l, r]的最小值。这个区间的长度是len = r - l + 1。
首先,我们找到最大的k,使得2^k <= len。这个k实际上是我们在预处理阶段计算出的最大的可以覆盖的区间长度。
然后,我们返回st[l][k]和st[r - (1 << k) + 1][k]中的最小值。这两个值分别表示从l开始长度为2^k的区间的最小值,和从r - 2^k + 1开始长度为2^k的区间的最小值。这两个区间的并集刚好覆盖了我们要查询的区间[l, r],并且可能有重叠。
这个方法的原理是利用了预处理阶段计算出的所有可能长度的区间的最小值,通过合并这些区间来得到任意长度的区间的最小值。这样,我们可以在O(1)的时间内完成查询。
首先,我们找到最大的k,使得2^k <= len。这个k实际上是我们在预处理阶段计算出的最大的可以覆盖的区间长度。
然后,我们返回st[l][k]和st[r - (1 << k) + 1][k]中的最小值。这两个值分别表示从l开始长度为2^k的区间的最小值,和从r - 2^k + 1开始长度为2^k的区间的最小值。这两个区间的并集刚好覆盖了我们要查询的区间[l, r],并且可能有重叠。
这个方法的原理是利用了预处理阶段计算出的所有可能长度的区间的最小值,通过合并这些区间来得到任意长度的区间的最小值。这样,我们可以在O(1)的时间内完成查询。