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;
}