數據結構——ST表(RMQ)

ST表類似樹狀數組、線段樹。
適用於解決區間最值得查詢得算法,預處理O(nlogn),查詢上ST表爲O(1),而線段樹爲O(logn)。但是ST表只能除了離線的,不能修改。

  1. 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])。當然也可以是最大值。
  2. 接下來就是查詢操作。
    一般情況下查詢的區間[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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章