• P1816 忠诚 ST表模版


    寒假学了ST表之后,一直没有写相关的题目,ST表的写法都快忘了,今天复习的时候,就做了几个题,来复习一下ST表。

    我不知道为什么题解里都用线段树来做,线段树不但慢,还不好写。这道题分明没有修改操作,用ST表离线处理之后用O(1)的复杂度来查询就能A了。

    ST表就是一个用来解决rmq(区间最值)问题的算法。ST表不支持在线修改。预处理时间复杂度O(nlogn),查询时间O(1)。

    ST表需要用到DP和倍增的思想,先建立一个二维数组st[i][j],表示从第i个元素开始的2的j次方个数的最小值。

     举个例子

    1 2 3 4 5 五个数

    st[2][2] 就是2 3 4 5这四个数中的最小值

    st[3][0]就是3这一个数中的最小值

    弄清楚st数组所代表的意义后,先把怎样求出st数组放在一边,来看一下如何利用st数组求解区间最值(RMQ)问题。


    对于一个询问,会有一个左端点,一个右端点,因为st表所表示的范围是不断倍增的,不一定有元素正好覆盖查询区间,就需要用两个区间覆盖查询区间,因为是最值问题,所以两个区间有交叉部分并不会影响结果,只需取一个k,使得2的k次方小于区间长度(右端点-左端点+1),并且使k尽可能的大。

    然后在st表中取两个元素,第一个元素的起始位置使区间的左端点,第二个元素的结束位置是区间的右端点,然后在在两个元素中取最小值。这个方法的正确性和实现方法都是显而易见的,结合代码都能理解,这里就不再赘述了。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,st[100001][21],ans[100001],a[100000],f1,f2,kkk;
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);    
            st[i][0]=a[i];    
        }
        for(int j=1;(1<<j)<=n;j++)
        for(int i=1;i<=n-(1<<j)+1;i++)
        st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&f1,&f2);
            kkk=0;
            while((1<<(kkk+1))<=(f2-f1+1))kkk++;
            ans[i]=min(st[f1][kkk],st[f2-(1<<kkk)+1][kkk]);
        }
        for(int i=1;i<=m;i++)
        printf("%d ",ans[i]);
        return 0;
    }
  • 相关阅读:
    精选30道Java笔试题解答
    ASM
    Java Decompiler Plugin For Eclipse IDE
    AMQ5540, AMQ5541 and AMQ5542, application did not supply a user ID and password, 2035 MQRC_NOT_AUTHORIZED
    Shell脚本中的export
    Linux set unset命令
    shell中${}的妙用
    ubuntu alsa2
    ubuntu alsa
    计算机启动boot
  • 原文地址:https://www.cnblogs.com/-cym/p/8503374.html
Copyright © 2020-2023  润新知