RMQ问题入门(sparse_table稀疏表)——UVA - 11235 Frequent values

RMQ问题就是range minimum query,范围最小值问题:给出n个元素的数组,要求查询操作query(l,r)来查询区间[l,r]内的最小值,同样,也可以拓展延伸到求最大值,求最大出现频率。


这类问题使用sparse_table算法可以做到O(nlogn)预处理时间复杂度,O(1)的查询时间复杂度。在这个二维数组构建的表中,d(i,j)表示从i开始,长度为2^j的范围内的最小值,因为2^32就已经是很大的数了,所以j一般开比较小就够用了,题目数据量范围大也不容易出现数组开不了这么大的情况。

void rmq_init(){
    for (int i = 0; i <n; i++){ d[i][0] = a[i]; }
    for (int j = 1; (1 << j) <= n; j++){
        for (int i = 0; i + (1 << j) - 1 <n; i++){
            d[i][j] = min(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int rmq(int l, int r){
    if (l > r)return 0;
    int k = 0;
    while ((1 << (k + 1)) <= r - l + 1)k++;
    return min(d[l][k], d[r - (1 << k)+1][k]);
}

这里给出了预处理和查询的代码,预处理就通过循环从j为0往上递推,每次d[i][j] = max(d[i][j - 1], d[i + (1 << (j - 1))][j - 1])这里max里面的两个区间是刚好相邻不重叠的,但是查询时候的区间可能会重叠,所以可能只能在求最大值最小值这类问题使用。

UVA - 11235 Frequent values

这题题意就是在非降序数列里查询区间内最频繁的出现次数,用到了游程编码将相同的数字化为一个点来建立稀疏表。因此在数据输入时处理一下然后问题就转化成类似RMQ的问题了。

#include<iostream>
#include<string.h>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
int n,q;
int d[100005][32];
int lef[100005], rig[100005], num[100005], val[100005], cou[100005];
int qqq;
void rmq_init(){
    for (int i = 0; i <=qqq; i++){ d[i][0] = cou[i]; }
    for (int j = 1; (1 << j) <= qqq+1; j++){
        for (int i = 0; i + (1 << j) - 1 <=qqq; i++){
            d[i][j] = max(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
        }
    }
}

int rmq(int l, int r){
    if (l > r)return 0;
    int k = 0;
    while ((1 << (k + 1)) <= r - l + 1)k++;
    return max(d[l][k], d[r - (1 << k)+1][k]);
}


int main(){
    int x, y;
    while (scanf("%d", &n), n){
        qqq = -1;
        scanf("%d", &q);
        for (int i = 1; i <= n; i++){
            scanf("%d", &x);
            if (qqq == -1 || x != val[qqq]){
                val[++qqq] = x; lef[qqq] = i; rig[qqq] = i; cou[qqq] = 1; num[i] = qqq;
            }
            else{
                cou[qqq]++; rig[qqq] = i; num[i] = qqq;
            }
        }
        rmq_init();
        int ans;
        for (int i = 0; i < q; i++){
            scanf("%d%d", &x, &y);
            if (num[x] == num[y]){
                ans = y - x + 1;
            }
            else{
                int l = num[x], r = num[y];
                ans = max(rig[l]-x+1,max(rmq(l+1,r-1),y-lef[r]+1));
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值