zoukankan      html  css  js  c++  java
  • 基于稀疏表(Sparse Table)的RMQ讲解

    基于稀疏表(Sparse Table)的RMQ需要先进行复杂度O(nlogn)的预处理,而后在查询[ql, qr]的最值时,计算出最大的满足ql + (1 << bit) <= qr的bit(复杂度O(loglogn)),即可在O(1)时间复杂度内查询,从而可以解决查询次数很多(如大于100万)的RMQ问题。

    我们定义t[i][j]为以 i 为左端点的长度为 2j 的闭区间(0 <= j, 2j <= n, 1 <= i <= n - 2j + 1)

    我们可以得到如下的一个稀疏表

    这样以来每个t[][]表示的都是一段长度为2的幂次的区间的最值。但考虑到实际查询的区间长度往往不是2的幂次,那么这个区间要如何表示呢?答案是一个不行,就来两个。把查询区间用两个区间的并来表示。为了确保两个区间的并恰好为查询区间,我们可以从左右边界向中间扫(如图)

    那么为了确保两个小区间可以包含整个大区间,小区间长度必然不小于原区间的一半,且区间长度为2的幂次。所以在RMQ中,我们首先要求出满足2<= qr - ql < 2j + 1 的j。也就是使得2j不超过(qr - ql)的最大的j。

    有了这种划分区间的思想,我们可以轻易地出状态转移公式

    t[i][j] = {t[i][j - 1], t[i + (1 << (j - 1))][j - 1]}; 

    对于每个查询,{dp[ql][j], dp[qr - (1 << j) + 1][j])就是答案了。//左右皆闭

    这样以来问题就仅剩下,如何高效地求解对应j呢?

    计算(qr - ql),然后二分求解即可

     1 int mbit(int a) {
     2     int l = 0, r = 16;
     3     while (l < r - 1) {
     4         int m = (l + r) / 2;
     5         if ((1 << m) <= a) {
     6             l = m;
     7         } else {
     8             r = m;
     9         }
    10     }
    11     return l;
    12 }
    View Code

    POJ-3264

    求解给定闭区间的最大值和最小值的题目

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <queue>
     6 #include <vector>
     7 #define max(x, y) (x > y ? x : y)
     8 #define min(x, y) (x > y ? y : x)
     9 #define INF 0x3f3f3f3f
    10 #define mod 1000000007
    11 typedef long long LL;
    12 using namespace std;
    13 
    14 const int maxn = 5e4 + 5;
    15 const int maxnn = 16;
    16 
    17 int n, m, c[maxn];
    18 int MAX[maxn][maxnn];
    19 int MIN[maxn][maxnn];
    20 int ql, qr, b;
    21 
    22 void init() {
    23     for (int i = 1; i <= n; i++) {
    24         MAX[i][0] = MIN[i][0] = c[i];
    25     }
    26     double limit = log(n) / log(2.0);
    27     for (int j = 1; j <= (int)limit; j++) {
    28         for (int i = 1; i + (1 << j) - 1 <= n; i++) {
    29             MAX[i][j] = max(MAX[i][j - 1], MAX[i + (1 << (j - 1))][j - 1]);
    30             MIN[i][j] = min(MIN[i][j - 1], MIN[i + (1 << (j - 1))][j - 1]);
    31         }
    32     }
    33 }
    34 
    35 int mbit(int a) {
    36     int l = 0, r = 16;
    37     while (l < r - 1) {
    38         int m = (l + r) / 2;
    39         if ((1 << m) <= a) {
    40             l = m;
    41         } else {
    42             r = m;
    43         }
    44     }
    45     return l;
    46 }
    47 
    48 int getmax() {
    49     return max(MAX[ql][b], MAX[qr - (1 << b) + 1][b]);
    50 }
    51 
    52 int getmin() {
    53     return min(MIN[ql][b], MIN[qr - (1 << b) + 1][b]);
    54 }
    55 
    56 int main(int argc, const char * argv[]) {
    57     scanf("%d%d", &n, &m);
    58     for (int i = 1; i <= n; i++) {
    59         scanf("%d", &c[i]);
    60     }
    61     init();
    62     while (m--) {
    63         scanf("%d%d", &ql, &qr);
    64         b = mbit(qr - ql);
    65         printf("%d
    ", getmax() - getmin());
    66     }
    67     return 0;
    68 }
    View Code

    下标是从0开始的,所以处理成了区间左闭右开的形式,稍微有点不同

     1 void init() {
     2     for (int i = 0; i < n; i++) { //
     3         MAX[i][0] = MIN[i][0] = c[i];
     4     }
     5     double limit = log(n) / log(2.0);
     6     for (int j = 1; j <= (int)limit; j++) {
     7         for (int i = 0; i + (1 << j) - 1 < n; i++) { //
     8             MAX[i][j] = max(MAX[i][j - 1], MAX[i + (1 << (j - 1))][j - 1]);
     9             MIN[i][j] = min(MIN[i][j - 1], MIN[i + (1 << (j - 1))][j - 1]);
    10         }
    11     }
    12 }
    13 
    14 
    15 int getmax() {
    16     return max(MAX[ql - 1][b], MAX[qr - (1 << b)][b]); //
    17 }
    18 
    19 int getmin() {
    20     return min(MIN[ql - 1][b], MIN[qr - (1 << b)][b]); //
    21 }
    View Code
  • 相关阅读:
    每日一水 POJ8道水题
    编译和使用 MySQL C++ Connector
    j2ee model1模型完成分页逻辑的实现 详解!
    DB查询分析器访问EXCEL时,要在表名前后加上中括弧或双引号
    指向结构体变量的指针
    EOSS V3.0 企业运营支撑系统(基于RBAC原理的权限管理)
    MybatisGen1.0 Mybatis JavaBean Mapper生成工具
    The table name must be enclosed in double quotation marks or sqare bracket while accessing EXCEL by
    资源-Android:Android
    软件-开发软件:Android Studio
  • 原文地址:https://www.cnblogs.com/xFANx/p/6901104.html
Copyright © 2011-2022 走看看