数据结构——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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值