• 浅谈-RMQ


    浅谈RMQ

    Today,我get到了一个新算法,开心....RMQ。

    今天主要说一下RMQ里的ST算法(Sparse Table)。

    RMQ(Range Minimum/Maximum Query),意思是对于一段区间,查询最大值最小值的一种数据结构。首先,我们很容易想到线段树,时空复杂度均为O(nlogn),但是RMQ的优越之处就在于它查询是O(1)的。

    首先,我们先说一下RMQ的大体思想。用动态规划的想法来预处理出一些强大的式子。我们定义f[i][j],这是RMQ算法最核心的地方,关于f数组的定义。我们容易想到是i到j之间的最小值,但是在转移或者是处理上都比较的不方便,那如果是从i开始的j个数的最值呢?也是有一些局限性,所以,我们给出了一种思想,叫做倍增的想法。就是说我f[i][j]表示的是从i开始的$2^j$个数的最值。这样的处理的好处在于什么呢?我们发现,我可以将全局的任意的$2^j$块都处理出来,所用到的就是f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);这个东西是我们是处理过的。显然,现在总区间内所有的$2^k$个数我们都处理过了。现在,我们思考如何查询。

    查询时,我们想到,需要查询的区间不可能就是$2^j$的整倍数区间。所以,我们应该怎么做呢?从需要查询区间的左端点向右弄一个$2^k$记录一下,右端点向左再记录一遍。我们现在想求出k是几。这就是为什么RMQ只能求最值,因为存在覆盖的问题对吧,所以,我们思考一下,这个k的值是不是固定的呢?显然是。为什么,我们想求出$2^k$必须满足什么条件

      1.$2^k$必须大于需要查询区间的一半。

      2.$2^k$还要不大于整个需要被查询得区间。
    这样来看,k就是最大的,且$2^k$不大于需要查询区间的长度。为什么此时的k-1不行,因为那样的话就会不满足第一个条件。所以,k是确定的。那么,k应该怎么求呢?此处切记,千万别用<cmath>,因为精度极其不准,我们采用o(n)预处理 log[i]=log[i>>1]+1。即可。

        最后,附上丑陋的版子.......

        预处理

     1 int n;
     2 scanf("%d",&n);
     3 for(int i=2;i<=n;i++) log[i]=log[i>>1]+1;
     4 for(int i=1;i<=n;++i)
     5 {
     6     scanf("%d",&a[i]);
     7 }
     8 for(int i=1;i<=n;i++)
     9 {
    10     f[i][0]=a[i];
    11 }
    12 for(int i=1;(1<<i)<=n;i++)
    13 {
    14     for(int j=1;j+(1<<i)-1<=n;j++)
    15     {
    16         f[j][i]=max(f[j][i-1],f[j+(1<<(i-1))][i-1]);
    17     }
    18 }

        查询

    1 int m;
    2 scanf("%d",&m);
    3 int x,y;
    4 for(int i=1;i<=m;i++)
    5 {
    6     scanf("%d%d",&x,&y);
    7     int len=log[y-x+1];
    8     printf("%d
    ",max(f[x][len],f[y-(1<<len)+1][len]));
    9 }

        小结,这种数据结构的想法非常重要,虽然在使用上有一些局限性,但是它的想法是极其值得借鉴的。

  • 相关阅读:
    SD卡测试
    测试人员可能会遇到的问题
    HDU 1024 Max Sum Plus Plus
    HDU 1176 免费馅饼
    HDU 1257 最少拦截系统
    HDU 1087 Super Jumping! Jumping! Jumping!
    poj 1328 Radar Installation
    poj 1753 Flip Game
    HDU 1003 Max Sum
    HDU 5592 ZYB's Premutation(BestCoder Round #65 C)
  • 原文地址:https://www.cnblogs.com/ShuraK/p/8278581.html
Copyright © 2020-2023  润新知