ST表类似树状数组、线段树。
适用于解决区间最值得查询得算法,预处理O(nlogn),查询上ST表为O(1),而线段树为O(logn)。但是ST表只能除了离线的,不能修改。
- ST表得构造采用DP的思想。主体为一个二维数组st[][],s[i][j] 表示 [i, i + 2^j - 1]区间的最值。
转移方程为:st[i][j] = min(st[i][j-1], st[i+2^(j-1)][j-1])。当然也可以是最大值。 - 接下来就是查询操作。
一般情况下查询的区间[a, b]不会满足正好[i, i+2^(j-1) ],那么就要将区间分为俩个(可能一头一尾会有重叠),[a,a+2^k -1]和[b - 2^k +1, b]。
k = floor(log(b-a+1)/log(2))。
ans = (st[a][k], st[b-(1<<k) + 1][k])。
习题:
1.luogu p3865 ST板子题
链接:luogu p3865
题意:n个数,m次查询, 每次查询给一个区间,让你求该区间里面的最大值。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+50;
int n, m;
int a[maxn];
int st[maxn][20];
void init(){
for(int i = 1; i <= n; i++){
st[i][0] = a[i];
}
for(int j = 1; (1<<j) <= n; j++){
for(int i = 1; i+(1<<j)-1 <= n; i++){
st[i][j] = max(st[i][j-1], st[i+(1<<j-1)][j-1]);
}
}
}
int RMQ(int x, int y){
int k = (int)(log(y-x+1)/log(2));
return max(st[x][k], st[y-(1<<k)+1][k]);
}
int main()
{
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
}
init();
for(int i = 1; i <= m; i++){
int x, y;
scanf("%d %d", &x, &y);
printf("%d\n", RMQ(x, y));
}
return 0;
}
2.HDU 3193 Find the hotel
链接:HDU 3193
题意:给定 n 个点对 ( pi , di ) ,求出所有的点对,使得对于当前点对来说,不存在其它点对的 p, d 比这个点对的都小。按照 p 优先,d 次先从小到大输出点对。
题解:将其按照p为第一优先级,d为第二优先级,从小到大排序,用ST表存d
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e4+50;
int n, m;
int st[maxn][20];
struct node{
int p, d;
}a[maxn], ans[maxn];
bool cmp(node x, node y){
if(x.p == y.p){
return x.d < y.d;
}
return x.p < y.p;
}
void init(){
fill(st[0], st[0]+(n+5)*20, 0x3f3f3f3f);
for(int i = 1; i <= n; i++){
st[i][0] = a[i].d;
}
for(int j = 1; (1<<j) <= n; j++){
for(int i = 1; i+(1<<j)-1 <= n; i++){
st[i][j] = min(st[i][j-1], st[i+(1<<j-1)][j-1]);
}
}
}
int RMQ(int x, int y){
int k=0;
while(1<<(k+1)<=y-x+1)k++;
return min(st[x][k], st[y-(1<<k)+1][k]);
}
int main()
{
while(scanf("%d", &n) != EOF){
for(int i = 1; i <= n; i++){
scanf("%d %d", &a[i].p, &a[i].d);
}
sort(a+1, a+n+1, cmp);
init();
int cur = 1, pos = 1;
for(int i = 1; i <= n; i++){
if(a[i].p != a[pos].p) pos = i;
if(RMQ(1, pos) >= a[i].d){
ans[i].p = a[i].p;
ans[i].d = a[i].d;
cur++;
}
}
printf("%d\n", cur-1);
for(int i = 1; i < cur; i++){
printf("%d %d\n", ans[i].p, ans[i].d);
}
}
return 0;
}
来源:CSDN
作者:放过@
链接:https://blog.csdn.net/wxy2635618879/article/details/104357715