zoukankan      html  css  js  c++  java
  • RMQ 解决区间查询问题

     线段树写法不管,比较灵活。这里主要讨论DP实现。

    其实单纯说RMQ解决的是区间最值查询是不准确的,只要满足一个区间的信息可以从它的覆盖区间获得(即[L,R]<=[L,r],[l,R] (l<=r) ,允许两个子区间重合)即可使用。重合不影响最值判断,所以最值查询是可以用RMQ的,其次如同区间gcd,重合区间也是不影响求值的。一样可以用RMQ。

    下面用RMQ的实现来解释上述结论:

    dp[i][j]表示以i起始,长度为2^j的线段信息。它可以划分为dp[i][j-1],dp[i+2^(j-1)][j-1],所以状态转移就出来,dp[i][j]=某种计算(dp[i][j-1],dp[i+2^(j-1)][j-1];

    查询的话,如果像线段树那样用递归分解区间求解,复杂度log级,因为是严格分离区间,所以不存在之前说的重合影响(所以线段树适用范围大啊)。而DP实现要求在O(1)时间给出答案,所以我们可以把查询区间分解为两个尽可能大的子区间(允许覆盖),这有个很简单的写法,对于区间L,R的查询,求一下k=log2(R-L+1),两个子区间为dp[L][k],dp[R-2^k+1][k];

    以区间gcd为例:

    LL lg2(LL p)//计算log2(n)
    {
        return (LL)(log(p) / log(2));
    }
    const LL len = 100005;//数据长度
    const LL bitlen = 25;//需要的位数
    LL n;
    LL dp[len][bitlen];//dp数组
    LL bit[bitlen];//预处理2^n
    void initRMQ()//初始化
    {
        for (LL j = 1; bit[j] < n; j ++)
            for (LL i = 0; i+bit[j] <= n; i++)
                dp[i][j] = gcd(dp[i][j - 1], dp[i + bit[j - 1]][j - 1]);
    }
    LL query(LL l, LL r)
    {
        LL mig = lg2(r - l + 1.0);
        return gcd(dp[l][mig], dp[r - bit[mig] + 1][mig]);
    }

    对于需要增删改的操作,显然是线段树比较合适,对于有大量查询操作的题目,RMQ可以有效降低时间(最近遇到的这类题目对时间空间要求都很高,写代码写丑一点就挂了。提醒自己多注意)。

  • 相关阅读:
    HDU 1124 Factorial
    hdu 1690 Bus System
    hdu 1113 Word Amalgamation
    POJ 2482 Stars in Your Window
    hdu 1385 ZOJ 1456 Minimum Transport Cost(经典floyd)
    hdu 1907 John
    VMware 虚拟机 安装 UBuntu 9.10 命令模式转换成窗口模试
    #pragma CODE_SEG __NEAR_SEG NON_BANKED详解
    Ubuntu 下Hadoop 伪分布式 hadoop0.20.2.tar.gz 的安装
    文件拷贝代码以及疑问
  • 原文地址:https://www.cnblogs.com/LukeStepByStep/p/7156405.html
Copyright © 2011-2022 走看看