RMQ 详解及 题目

系统 2285 0

RMQ(Range Minimum/Maximum Query)问题:
 

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

预处理:
预处理使用DP的思想,f(i, j)表示[i, i+2^j - 1]区间中的最小值,我们可以开辟一个数组专门来保存f(i, j)的值。
例如,f(0, 0)表示[0,0]之间的最小值,就是num[0], f(0, 2)表示[0, 3]之间的最小值, f(2, 4)表示[2, 17]之间的最小值
注意, 因为f(i, j)可以由f(i, j - 1)和f(i+2^(j-1), j-1)导出, 而递推的初值(所有的f(i, 0) = i)都是已知的
所以我们可以采用自底向上的算法递推地给出所有符合条件的f(i, j)的值。

        
          1
        
        
          for
        
        (
        
          int
        
         i=
        
          1
        
        ;i<=n;i++
        
          ) 


        
        
          2
        
            f[i,
        
          0
        
        ]:=
        
          a[i];


        
        
          3
        
        
          4
        
        
          for
        
        (
        
          int
        
         j=
        
          1
        
        ;j<=log(n)/log(
        
          2
        
        );j++
        
          )


        
        
          5
        
        
          {


        
        
          6
        
        
          for
        
        (
        
          int
        
         i=
        
          1
        
        ;i<=n+
        
          1
        
        -
        
          1
        
        <<j;j++
        
          ) 


        
        
          7
        
              f[i,j]=max(f[i,j-
        
          1
        
        ],f[i+
        
          1
        
        <<(j-
        
          1
        
        ),j-
        
          1
        
        
          ]);  


        
        
          8
        
         };
      

 

查询:
假设要查询从m到n这一段的最小值, 那么我们先求出一个最大的k, 使得k满足2^k <= (n - m + 1).
于是我们就可以把[m, n]分成两个(部分重叠的)长度为2^k的区间: [m, m+2^k-1], [n-2^k+1, n];


而我们之前已经求出了f(m, k)为[m, m+2^k-1]的最小值, f(n-2^k+1, k)为[n-2^k+1, n]的最小值

        
          1
        
        
          long
        
         query(
        
          long
        
         l,
        
          long
        
        
           r)


        
        
          2
        
        
          {


        
        
          3
        
        
          long
        
         x=log(r-l+
        
          1
        
        )/log(
        
          2
        
        
          );


        
        
          4
        
        
          return
        
         (max(f[l,x],f[r+
        
          1
        
        -
        
          1
        
        <<
        
          x,x]));


        
        
          5
        
         }
      

 


我们只要返回其中更小的那个, 就是我们想要的答案, 这个算法的时间复杂度是O(1)的.
例如, rmq(0, 11) = min(f(0, 3), f(4, 3))

感想:对于一个数组里的固定长度的区间,可以只开一个n*1维数组,算f(i,j)的时候可以将f(i,j-1)覆盖,因为用到的只是上一列的情况。

 

题目:

poj 3368 Frequent values

http://poj.org/problem?id=3368

 

题意 : 给定 一个 递增的数组 a   给出 q 次询问 求出 l  到 r  最多的     数字相同的个数

 

如 :10 3 -1 -1 1 1 1 1 3 10 10 10

输入 1 10

输出  4

  1 到10 出现最多的是 1 出现了 4 次

 

题解: 将 连续相同的点 缩成一个节点 ,这个节点包括三个部分  初始位置 ,结束位置 ,个数
  那么询问时 包括三种情况
  1:l 和 r同属于  一个节点   那么 ans = r - l + 1
   
  2: 属于相邻的连个节点  ans =  max ( p[hash[l]].t - l +1,r - p[hash[r]].s + 1);
  3: 属于  l 和 r之间有好几个节点   hash[l]+1  到 hash[r] - 1 的最大值 和 情况 2 进

View Code
          
             1
          
           #include<cstdio>


          
             2
          
           #include<cmath>


          
             3
          
           #include<cstring>


          
             4
          
           #include<iostream>


          
             5
          
           #include<algorithm>


          
             6
          
           #include<
          
            set
          
          >


          
             7
          
           #include<map>


          
             8
          
           #include<queue>


          
             9
          
           #include<vector>


          
            10
          
           #include<
          
            string
          
          >


          
            11
          
          
            #define
          
           Min(a,b) a<b?a:b


          
            12
          
          
            #define
          
           Max(a,b) a>b?a:b


          
            13
          
          
            #define
          
           CL(a,num) memset(a,num,sizeof(num));


          
            14
          
          
            #define
          
           maxn  100010


          
            15
          
          
            #define
          
           inf 9999999


          
            16
          
          
            17
          
          
            #define
          
            mod   9973


          
            18
          
          
            #define
          
           ll  long long


          
            19
          
          
            using
          
          
            namespace
          
          
             std;


          
          
            20
          
          
            int
          
          
             hash[maxn],a[maxn];


          
          
            21
          
          
            int
          
           dp[maxn][
          
            30
          
          
            ],id;


          
          
            22
          
          
            23
          
          
            struct
          
          
             node


          
          
            24
          
          
            {


          
          
            25
          
          
            int
          
          
             s;


          
          
            26
          
          
            int
          
          
             t;


          
          
            27
          
          
            int
          
          
             w;


          
          
            28
          
          
            29
          
          
            }p[maxn];


          
          
            30
          
          
            void
          
          
             rmq_init()


          
          
            31
          
          
            {


          
          
            32
          
          
            int
          
          
             i , j;


          
          
            33
          
          
            34
          
          
            for
          
          ( i = 
          
            0
          
          ; i <= id;++i)dp[i][
          
            0
          
          ] =
          
             p[i].w;


          
          
            35
          
          
            int
          
           k = log(
          
            double
          
          (id+
          
            1.0
          
          ))/log(
          
            2.0
          
          );
          
            //
          
          
            36
          
          
            37
          
          
            for
          
          ( i = 
          
            1
          
          ;i <= k; ++
          
            i)


          
          
            38
          
          
                {


          
          
            39
          
          
            int
          
           s = (
          
            1
          
           << i-
          
            1
          
          ) - 
          
            1
          
          
            ;


          
          
            40
          
          
            for
          
          (j = 
          
            1
          
          ;j + (
          
            1
          
           << i)-
          
            1
          
           <= id ;++
          
            j)


          
          
            41
          
          
                    {


          
          
            42
          
                       dp[j][i] = max(dp[j][i - 
          
            1
          
          ],dp[j + s ][i - 
          
            1
          
          
            ]);


          
          
            43
          
          
                    }


          
          
            44
          
          
                }


          
          
            45
          
          
            }


          
          
            46
          
          
            int
          
          
            get
          
          (
          
            int
          
           l,
          
            int
          
          
             r)


          
          
            47
          
          
            {


          
          
            48
          
          
            int
          
           k = log(
          
            double
          
          (r - l +
          
            1.0
          
          ))/log(
          
            2.0
          
          );
          
            //
          
          
            求的是 求出最大的k,满足2^k<=R-L+1
          
          
            49
          
          
            int
          
           s = 
          
            1
          
           <<
          
             k;


          
          
            50
          
          
            return
          
           max(dp[l][k],dp[r - s + 
          
            1
          
          
            ][k]);


          
          
            51
          
          
            }


          
          
            52
          
          
            int
          
          
             main()


          
          
            53
          
          
            {


          
          
            54
          
          
            int
          
          
             n,m,i,l,r;


          
          
            55
          
          
            while
          
          (scanf(
          
            "
          
          
            %d
          
          
            "
          
          ,&
          
            n),n)


          
          
            56
          
          
                {


          
          
            57
          
                   scanf(
          
            "
          
          
            %d
          
          
            "
          
          ,&
          
            m);


          
          
            58
          
          
            for
          
          ( i = 
          
            1
          
          ;i <=n; ++i)scanf(
          
            "
          
          
            %d
          
          
            "
          
          ,&
          
            a[i]);


          
          
            59
          
          
            60
          
                   memset(p,
          
            0
          
          ,
          
            sizeof
          
          
            (p));


          
          
            61
          
                    id = 
          
            1
          
          
            ;


          
          
            62
          
                   p[
          
            1
          
          ].s = 
          
            1
          
          
            ;


          
          
            63
          
          
            64
          
          
            for
          
          ( i = 
          
            1
          
          ; i <= n ;++
          
            i)


          
          
            65
          
          
                    {


          
          
            66
          
                       hash[i] =
          
             id ;


          
          
            67
          
                       p[id].w++
          
            ;


          
          
            68
          
          
            if
          
          ( a[i] != a[i+
          
            1
          
          ] || i ==
          
             n)


          
          
            69
          
          
                        {


          
          
            70
          
                           p[id].t =
          
             i;


          
          
            71
          
          
            if
          
          (i == n)
          
            break
          
          
            ;


          
          
            72
          
                           id++
          
            ;


          
          
            73
          
                           p[id].s = i + 
          
            1
          
          
             ;


          
          
            74
          
          
            75
          
          
                        }


          
          
            76
          
          
            77
          
          
                    }


          
          
            78
          
          
                     rmq_init();


          
          
            79
          
          
            80
          
          
            while
          
          ( m--
          
            )


          
          
            81
          
          
                     {


          
          
            82
          
                        scanf(
          
            "
          
          
            %d%d
          
          
            "
          
          ,&l,&
          
            r);


          
          
            83
          
          
            if
          
          (hash[l] == hash[r])printf(
          
            "
          
          
            %d\n
          
          
            "
          
          ,r - l + 
          
            1
          
          
            );


          
          
            84
          
          
            else
          
          
            85
          
          
                         {


          
          
            86
          
          
            int
          
           num1 = p[hash[l]].t - l +
          
            1
          
          
            ;


          
          
            87
          
          
            int
          
           num2 = r - p[hash[r]].s + 
          
            1
          
          
            ;


          
          
            88
          
          
            int
          
           num3 = 
          
            0
          
          
            ;


          
          
            89
          
          
            if
          
          (hash[r] - hash[l] > 
          
            1
          
          
            )


          
          
            90
          
                           num3 = 
          
            get
          
          (hash[l]+
          
            1
          
          ,hash[r]-
          
            1
          
          
            );


          
          
            91
          
          
            int
          
           ans =
          
             max(max(num1,num2),num3);


          
          
            92
          
                           printf(
          
            "
          
          
            %d\n
          
          
            "
          
          
            ,ans);


          
          
            93
          
          
                         }


          
          
            94
          
          
                     }


          
          
            95
          
          
                }


          
          
            96
          
           }
        

 

 

poj  3264    Balanced Lineup

http://poj.org/problem?id=3264

 

题意 : 给定 一段数   q此次询问   求出  l 到 r 的  最大值 和最小值的

 

View Code
          #include<cstdio>
          
            

#include
          
          <cstring>
          
            

#include
          
          <iostream>
          
            

#include
          
          <algorithm>
          
            

#include
          
          <
          
            set
          
          >
          
            

#include
          
          <map>
          
            

#include
          
          <queue>
          
            

#include
          
          <vector>
          
            

#include
          
          <
          
            string
          
          >


          
            #define
          
           Min(a,b) a<b?a:b


          
            #define
          
           Max(a,b) a>b?a:b


          
            #define
          
           CL(a,num) memset(a,num,sizeof(num));


          
            #define
          
           maxn  60000


          
            #define
          
           inf 9999999




          
            #define
          
            mod   9973


          
            #define
          
           ll  long long


          
            using
          
          
            namespace
          
          
             std;


          
          
            int
          
           dp1[maxn][
          
            30
          
          ],dp2[maxn][
          
            30
          
          
            ],a[maxn];


          
          
            int
          
          
             n,m;


          
          
            void
          
          
             RMQ_init()

{

    
          
          
            int
          
           temp = 
          
            0
          
          
            ,i,j,s;

    
          
          
            while
          
          ( 
          
            1
          
          << temp < n)temp++
          
            ;



    
          
          
            for
          
          (i = 
          
            0
          
          ;i <= n; ++i)dp1[i][
          
            0
          
          ] = dp2[i][
          
            0
          
          ] =
          
             a[i];



    
          
          
            for
          
          (i = 
          
            1
          
          ; i <= temp ; ++
          
            i)

    {

         s 
          
          = 
          
            1
          
           << (i-
          
            1
          
          
            );

        
          
          
            for
          
          (j = 
          
            0
          
          ; j + s <= n;++
          
            j)

        {

             dp1[j][i] 
          
          = max(dp1[j][i-
          
            1
          
          ],dp1[j + s][i-
          
            1
          
          
            ]);

             dp2[j][i] 
          
          = min (dp2[j][i-
          
            1
          
          ],dp2[j + s][i - 
          
            1
          
          
            ]);

        }

    }

}


          
          
            int
          
          
            get
          
           (
          
            int
          
           l,
          
            int
          
          
             r)

{

    
          
          
            int
          
           k = r - l + 
          
            1
          
          
            ;

    
          
          
            int
          
           tmp = 
          
            0
          
          
            ;





    
          
          
            while
          
          (
          
            1
          
           << tmp < k ) tmp++
          
            ;

    tmp
          
          --
          
            ;

    
          
          
            int
          
           s = 
          
            1
          
           <<
          
             tmp;

    
          
          
            int
          
           mx = max(dp1[l][tmp],dp1[r + 
          
            1
          
           -
          
             s][tmp]);

    
          
          
            int
          
           mi = min(dp2[l][tmp],dp2[r + 
          
            1
          
           -
          
            s ][tmp]);



    
          
          
            return
          
           mx -
          
             mi ;



}


          
          
            int
          
          
             main()

{

    
          
          
            int
          
          
             i, l,r;

    
          
          
            while
          
          (scanf(
          
            "
          
          
            %d%d
          
          
            "
          
          ,&n,&m)!=
          
            EOF)

    {

        
          
          
            for
          
          (i = 
          
            1
          
          ;i <= n; ++
          
            i)

        scanf(
          
          
            "
          
          
            %d
          
          
            "
          
          ,&
          
            a[i]);



        RMQ_init();



        
          
          
            while
          
          (m--
          
            )

        {

            scanf(
          
          
            "
          
          
            %d%d
          
          
            "
          
          ,&l,&
          
            r);

            
          
          
            int
          
           ans = 
          
            get
          
          
            (l ,r);

           printf(
          
          
            "
          
          
            %d\n
          
          
            "
          
          
            ,ans);



        }

    }



}
          
        

 

 

 

 

 

RMQ 详解及 题目


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论