RMQ问题的Sparse-Table算法

范围最小值问题(Range Minimum Query)

给出一个n个元素的数组,设计数据结构使得支持查询操作Query(L,R) 计算[L,R]中最小值

Tarjan的Sparse-Table算法预处理时间为O(nlogn) 查询只需要O(1)而且常数很小。

假设dp[i][j]表示从第i个数开始的2^j个数的最小值。

有下列公式:

dp[i][j] = min(dp[i,j-1],dp[i+2^(j-1)][j-1])

公式解释:

dp[i][j]表示s[i] s[i+1]…s[i+2^j-1]这一段的最小值

dp[i][j-1]表示s[i] s[i+1]…s[i+2^(j-1)-1]这一段的最小值

dp[i+2^(j-1)][j-1]表示s[i+2^(j-1)] s[i+2^(j-1)+1]…s[i+2^j-1]这一段的最小值

可以看出,后两者的和刚刚好覆盖了dp[i][j]。

注意2^j<=n 因此dp数组的元素个数不超过nlogn,而每一项都可以在常数时间计算完毕,所以总时间为O(nlogn)

void RMQ_init(const vector<int> &A)
{
    int n = A.size();
    for(int i = 0 ; i < n ; i ++) dp[i][0] = A[i];
    for(int j = 1 ; (1<<j) <= n ; j ++) {
        for(int i = 0 ; i+(1<<j)-1 < n ; i ++) {
            dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
}

查询操作也很简单,令k为满足2^k <= R-L+1的最大整数。

所以以L开头,以R结尾的两个区间合起来即覆盖了查询区间[L,R]

int RMQ(int L,int R)
{
    int k = 0;
    while((1<<(k+1)) <= R-L+1) k ++;
    return min(dp[L][k],dp[R-(1<<k)+1][k]);
}

NOJ1042 裸RMQ问题的Sparse-Table实现

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 10010;
int n;
int s[maxn];
int dp[maxn][15];
int query(int a,int b)
{
    int k = 0;
    while(1<<(k+1) <= b-a+1) k++;
    return min(dp[a][k],dp[b-(1<<k)+1][k]);
}
int main()
{
    scanf("%d",&n);
    for(int i = 1 ; i <= n ; i ++) scanf("%d",&s[i]);
    for(int i = 1 ; i <= n ; i ++) dp[i][0] = s[i];
    for(int j = 1 ; (1<<j) <= n ; j ++) {
        for(int i = 1 ; i+(2<<(j-1))-1 <= n ; i ++) {
            dp[i][j] = min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
        }
    }
    int q;
    scanf("%d",&q);
    while(q--) {
        int a,b;
        scanf("%d%d",&a,&b);
        printf("%d\n",query(a,b));
    }
    return 0;
}
时间: 2024-10-20 11:34:17

RMQ问题的Sparse-Table算法的相关文章

POJ 3264 RMQ Spare Table算法

今天下午大帝讲的,我以前也不懂,所以也就跟着学学了,把中间的那个状态转移方程学错了好几次,于是就wa了 好几发. #include<iostream> #include<cstdio> #include<algorithm> #define maxn 200010 using namespace std; int a[maxn],m,n,b[maxn],fl[maxn][50],fr[maxn][50]; void solve() { b[1]=0;//其实就是用来计算

图论学习十之Sparse table

ST表 无修改区间最值询问问题 • 给出一个数组a[1..N] • Q个询问,每次询问每次询问区间[x,y]最大值. • N,Q <= 100000 St表的递推 • 用st[k][i]表示从i开始连续2^k个元素的最值. • 得出递推式 • st[k+1][i]=max(st[k][i], st[k][i+2^k]);(假设求最大值) • 从小到大枚举k,再枚举i. • 那么预处理出上面这个数组的复杂度为O(nlogn) .   询问操作 • 找出最大的k使得 2^k<=y-x+1 • 注意

ST算法(Sparse Table)

RMQ问题: 给定一个序列,每次询问一个区间最小值 / 最大值. 没有修改. //拿区间最大值来举例. memset(ans, -INF, sizeof(ans)); for (int i = 1; i <= n; i++) ans[i][0] = a[i]; for (int j = 1; (1<<j) <= n; j++) //枚举长度为2^j的区间 for (int i = 1; i+(1<<j)-1 <= n; i++) //枚举区间起点 ans[i][j

散列表(hash table)&mdash;&mdash;算法导论(13)

1. 引言     许多应用都需要动态集合结构,它至少需要支持Insert,search和delete字典操作.散列表(hash table)是实现字典操作的一种有效的数据结构. 2. 直接寻址表     在介绍散列表之前,我们前介绍直接寻址表.     当关键字的全域U(关键字的范围)比较小时,直接寻址是一种简单而有效的技术.我们假设某应用要用到一个动态集合,其中每个元素的关键字都是取自于全域U={0,1,-,m-1},其中m不是一个很大的数.另外,假设每个元素的关键字都不同.    为表示动

Sparse Table讲解

Sparse Tabel名为稀疏表,又称为ST表,可以在O(1)的时间复杂度下完成查询区间最值,相比线段树和树状数 组,效率提升了不少.ST表本质上是一个很经典的dp,通过预处理完成O(1)的查询.既然是个dp,那我们来看下dp的 定义吧(下面以查询区间最大值为例). dp[i][j]:表示以i为起点,长度为2^j的区间最值 那么我们很容易得出状态转移方程:dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]),这里解释下状态转移

人造奇迹——二进制位运算的运用

最后更新:2014年4月30日 1.位运算包括: 这个我觉得大家都会我就随便说下: 位与&,如 101 & 110 = 100 位或|,如 100 | 110 = 110 位非~,如 ~101 = 010 位异或^,如 101 ^ 110 = 011 左移<<,如 011 << 1 = 110 右移>>,如 110 >> 1 = 011 其中,负数位运算的时候,用的是补码而不是原码请注意. 左移的时候,高位溢出的将会被舍弃,低位补0.如 11

RMQ问题ST算法 (还需要进一步完善)

/* RMQ(Range Minimum/Maximum Query)问题: RMQ问题是求给定区间中的最值问题.当然,最简单的算法是O(n)的,但是对于查询次数很多(设置多大100万次),O(n)的算法效率不够.可以用线段树将算法优化到O(logn)(在线段树中保存线段的最值).不过,Sparse_Table算法才是最好的:它可以在O(nlogn)的预处理以后实现O(1)的查询效率.下面把Sparse Table算法分成预处理和查询两部分来说明(以求最小值为例). 预处理: 预处理使用DP的思

RMQ_第一弹_Sparse Table

title: RMQ_第一弹_Sparse Table date: 2018-09-21 21:33:45 tags: acm RMQ ST dp 数据结构 算法 categories: ACM 概述 RMQ (Range Minimum/Maximum Query) 从英文便可以看出这个算法的主要是询问一个区间内的最值问题,,, 暑假集训的时候学习了 线段树 ,,, 也可以对给定数组查询任意区间的最值问题,,,, 这两个主要的区别就是 线段树 可以进行单点的修改操作,,,而 Sparse Ta

hdu 4603 Color the Tree 2013多校1-4

这道题细节真的很多 首先可以想到a和b的最优策略一定是沿着a和b在树上的链走,走到某个点停止,然后再依次占领和这个点邻接的边 所以,解决这道题的步骤如下: 预处理阶段: step 1:取任意一个点为根节点,找出父子关系并且对这个树进行dp,求出从某个节点出发往下所包含的所有边的权值总和  复杂度O(n) step 2:从tree dp 的结果中计算对于某个节点,从某条边出发所包含的边的综合,并且对其从大到小进行排序 复杂度O(n*logn) step 3:dfs求出这颗树的欧拉回路,以及每个点的

转 acm历程 置顶帖

作者情况和我差不多 期望可以激励自己 转 http://blog.csdn.net/yueqiq/article/details/7623176 首先,我想说的就是,我是一个很普通的ACMer,高中没有参加过任何计算机和数学竞赛的经历,也没有ben那样过人的天资,努力至今也未能取得什么成绩,我之所以写下这篇文章,只是希望给刚进大学或者刚进ACM队的同学一点小小的帮助,希望你们可以少走一些弯路,更希望你们可以帮助华理取得我没能取得的辉煌. (1).起步阶段我是从大二开始接触ACM的,要说基础的话就