zoukankan      html  css  js  c++  java
  • [OI学习笔记]st表

    用来查询区间最值(区间和,差等要处理重复部分)

    下面均以以最大值为例

    初始化 0(nlogn)

    设st[i][k]为下标i开始的2k个元素的最值

    则: st[i][k]=max{st[i][k-1],st[i+2k-1][k-1]}

    即区间[i,i+2k -1]的前一半和后一半的最值取最大

    查询 O(1)

    对于区间[l,r],区间长度len=r-l+1;找到满足2p <=len的最大p

    最大值ans=max{st[l][p],st[r-2p +1][p]} 

    显然,当2p !=len时,区间[l,l+p-1]和[r-2p +1][r]有重叠

    这也是为什么前面说区间和,差等要处理重复部分。

    2p <=len的p的最大值p <=log2len

    p=⌊log2len⌋  (下取整)

    代码:

    (注意第12行下标范围是i+(1<<k)-1<=n)

    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    using namespace std;
    
    int st[100010][21],n;//st的第二维取到log2(10010)即可 
    
    void init(){
        for(int k=1;(1<<k)<=n;k++)
            for(int i=1;i+(1<<k)-1<=n;i++)
                st[i][k]=max(st[i][k-1],st[i+(1<<(k-1))][k-1]);
    }
    
    int ask(int l,int r){
        int len=r-l+1;
        //int p=(int)log((double)(len))/log(2.0);//满足2^p<=r-l+1的最大p
        int p=log2(len);
        return max(st[l][p],st[r-(1<<p)+1][p]); 
    }
    
    //以最大值为例 
    int main(){
        int m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&st[i][0]);
        init();
        for(int i=1;i<=m;i++){
            int l,r;
            scanf("%d%d",&l,&r);
            int ans=ask(l,r);
            printf("%d
    ",ans);
        }
        return 0;
    }
    本篇文章为SHINE_GEEK原创,转载请注明来源!
    written_by:SHINE_GEEK

    -------------------------------------
    签名:自己选的路,跪着也要走完;理想的实现,需要不懈奋斗!
    -------------------------------------
  • 相关阅读:
    JQuery empty方法和remove方法的区别,使用remove清除之前的文本内容??
    乙_1023 组个最小数 (20分)
    乙_1022 D进制的A+B (20分)
    乙_1021 个位数统计 (15分)
    乙_1020 月饼 (25分)
    乙_1013 数素数 (20分)
    乙_1009 说反话 (20分)
    乙_1008 数组元素循环右移问题 (20分)
    乙_1007 素数对猜想 (20分)
    乙_1005 继续(3n+1)猜想 (25分)
  • 原文地址:https://www.cnblogs.com/sjrb/p/10375723.html
Copyright © 2011-2022 走看看