zoukankan      html  css  js  c++  java
  • 【BZOJ1067】[SCOI2007] 降雨量(RMQ+分类讨论)

    点此看题面

    大致题意:请你判断“(x)年是自(y)年以来降雨量最多的”这句话的真假。

    离散化/(lower\_bound)

    首先,考虑到年份的范围非常大,便可以离散化。

    而我比较懒,反正题目中说了年份是递增的,因此我直接用了(C++)自带的(lower\_bound)

    (RMQ)

    这题还需要使用的一个算法便是(RMQ)

    这应该是一个比较基础的算法吧,这里就不多加介绍了。

    至于哪里需要使用,后面你就知道了。

    分类讨论

    考虑如果是(false),则无非有(3)种情况:

    1. 左边界的降雨量已知且小于等于左右边界间的最大降雨量。
    2. 右边界的降雨量已知且小于等于左右边界间的最大降雨量。
    3. 左、右边界降雨量皆已知且左边界降雨量小于右边界降雨量。

    这里要求区间最大降雨量,就需要使用前面提到过的(RMQ)了。

    注意(RMQ)查询的区间边界的设定。假设(dx,dy)分别为(x,y)离散化后的值,则我们求最大值时不能把左右边界算在内。

    对于(dx),若其恰好在左边界上,则查询时须加(1),否则其位置必大于左边界,无需加(1)

    对于(dy),若其恰好在有边界上,则查询时须减(1),否则其位置必大于右边界,同需减(1)。可得结论,(dy)必减(1)

    在确保不是(false)的前提下,考虑如果是(Maybe),有(2)种情况:

    1. 左边界降雨量未知或右边界降雨量未知。
    2. 左右边界间存在降雨量未知。

    其中第(2)种情况我们可以通过比较左右边界离散化前后的差值是否一样,从而进行判断。

    如果不是(false)也不是(maybe),则自然就是(true)

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50000
    #define max(x,y) ((x)>(y)?(x):(y))
    #define GetPos(x) (lower_bound(s+1,s+n+1,data(x))-s)
    #define Maybe {puts("maybe");continue;}
    #define False {puts("false");continue;}
    #define True {puts("true");continue;}
    using namespace std;
    int n;
    struct data 
    {
        int Year,Rain;I data(CI x=0,CI y=0):Year(x),Rain(y){}
        I bool operator < (Con data& t) const {return Year^t.Year?Year<t.Year:Rain<t.Rain;}
    }s[N+5];
    class FastIO
    {
        private:
            #define FS 100000
            #define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
            #define tn (x<<3)+(x<<1)
            #define D isdigit(c=tc())
            int f;char c,*A,*B,FI[FS];
        public:
            I FastIO() {A=B=FI;}
            Tp I void read(Ty& x) {x=0,f=1;W(!D) f=c^'-'?1:-1;W(x=tn+(c&15),D);x*=f;}
            Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    }F;
    class RMQ//RMQ求区间最值
    {
        private:
            static const int SZ=N,Log=16;int Log2[SZ+5],Max[SZ+5][Log+5];
        public:
            I void Init(CI n,data* s)//初始化
            {
                RI i,j;for(i=1;i<=n;++i) Max[i][0]=s[i].Rain;for(i=2;i<=n;++i) Log2[i]=Log2[i>>1]+1;
                for(j=1;(1<<j)<=n;++j) for(i=1;i+(1<<j)<=n;++i) Max[i][j]=max(Max[i][j-1],Max[i+(1<<j-1)][j-1]);
            }
            I int GetMax(CI l,CI r) {if(l>r) return 0;RI k=Log2[r-l+1];return max(Max[l][k],Max[r-(1<<k)+1][k]);}//区间求Max
    }R;
    int main()
    {
        RI Qtot,i,x,y,dx,dy,dv;for(F.read(n),i=1;i<=n;++i) F.read(s[i].Year,s[i].Rain);//读入数据
        R.Init(n,s),F.read(Qtot);W(Qtot--)//处理询问
        {
            F.read(x,y),dx=GetPos(x),dy=GetPos(y),dv=R.GetMax(s[dx].Year^x?dx:dx+1,dy-1);//读入x,y,dx,dy表示离散化后的位置,dv表示左右边界间的最大降雨量
            if(!(s[dx].Year^x)&&s[dx].Rain<=dv) False;if(!(s[dy].Year^y)&&s[dy].Rain<=dv) False;//判断左、右边界的降雨量已知且小于等于左右边界间的最大降雨量的情况
            if(!(s[dx].Year^x)&&!(s[dy].Year^y)&&s[dx].Rain<s[dy].Rain) False;//判断左、右边界降雨量皆已知且左边界降雨量小于右边界降雨量的情况
            if(s[dx].Year^x||s[dy].Year^y||(y-x)^(dy-dx)) Maybe;True;//判断左边界降雨量未知或右边界降雨量未知或左右边界间存在降雨量未知的情况
        }return 0;
    }
    
  • 相关阅读:
    BZOJ 1257 [CQOI2007]余数之和sum | 数论
    【模板】网络流-最大流模板(Dinic)
    BZOJ 3230 相似子串 | 后缀数组 二分 ST表
    BZOJ 1031 [JSOI2007]字符加密Cipher | 后缀数组模板题
    后缀数组模板(全注释)
    BZOJ 3190 赛车 | 计算几何
    BZOJ 1007 水平可见直线 | 计算几何
    BZOJ 4753 [Jsoi2016]最佳团体 | 树上背包 分数规划
    BZOJ 4898 [APIO2017] 商旅 | SPFA判负环 分数规划
    BZOJ 2527 Meteors | 整体二分
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ1067.html
Copyright © 2011-2022 走看看