算法 {RMQ(可重复覆盖的区间查询)}

算法 {RMQ(可重复覆盖的区间查询)}

RMQ(可重复覆盖的区间查询)

定义

给定一维数组Array[], 对于查询Array[l...r]这个区间, 他可分成两个 长度为2次幂可重复覆盖的子区间L,R (比如[2,3,4,5,6] 分成[2,3,4,5][3,4,5,6]), 通过预处理子区间, 通过Merge( L.info, R.info)来得到整个区间的信息;

算法

模板

代码
namespace ___RMQ{
//< #代码#: `___RMQ::Initialize()` -> `static ___RMQ::RMQ< ___RMQ::__Info_max_<int> > Rmq;` -> `Rmq.Initialize<int>( A.data(), A.size());`;
    static constexpr int __MaxLength_ = ?;
    static int __Log[ 1+__MaxLength_]; // Log[1-2]=0, Log[3-4]=1, Log[5-8]=2, Log[9-16]=3;
    void Initialize(){
        __Log[1] = 0;  __Log[2] = 0;
        for( int pow2 = 2, i = 3; i < __MaxLength_; ++i){
             if( i == pow2*2){ pow2*=2;}  __Log[i] = __Log[i-1];  if( (i-1) == pow2){ ++ __Log[i];}
        }
    }
    template< class _Info_> struct RMQ{ // 可重复覆盖问题
        static constexpr int __GetPowerRange( int _length){ int ANS = 0; while(1){ if((1<<ANS)*2 >= _length){ break;} ++ANS;} return ANS;}

        _Info_ __Dp[ __MaxLength_][ 1 + __GetPowerRange(__MaxLength_)]; // `Dp[i][j]`表示`[i,i+1,...,(i+(1<<j)-1)]`这个子区间;
        int __Length, __LogRange;

        template< class _TypeArray_> void Initialize( _TypeArray_ const* _arr, int _length){
            ASSERT_SYSTEM_( _length <= __MaxLength_);
            __Length = _length;  __LogRange = __GetPowerRange( _length);

            for( int i = 0; i < _length; ++i){ __Dp[i][0].Initialize_oneElement( _arr[i]);}
            for( int p = 1; p <= __LogRange; ++p){
                for( int l = 0; l + (1<<p) <= _length; ++l){
                    __Dp[ l][ p] = _Info_::Merge( __Dp[l][ p-1], __Dp[ l+(1<<(p-1))][ p-1]);
                }
            }
        }
        _Info_ Query( int _l, int _r){
            ASSERT_SYSTEM_( _l>=0 && _l<=_r && _r<__Length);
            int p = __Log[ _r-_l+1];
            return _Info_::Merge( __Dp[ _l][ p], __Dp[ _r-(1<<p)+1][ p]);
        }
    };

    template< class _TypeArray_> struct __Info_max_{ // 这里的`TypeArray` 和 `RMQ::Initialize<TypeArray>`是对应的;
        _TypeArray_ data;
        void Initialize_oneElement( _TypeArray_ const& _v){
            data = _v;
        }
        static __Info_max_ Merge( __Info_max_ const& _info0, __Info_max_ const& _info1){ // 比如数组`[...,x0,x1,x2,...]`, 假设`info0==[x0,x1], info1==[x1,x2]`,那么 你的返回值就是`[x0,x1,x2]`对应的`info`;
            __Info_max_ RET;
            RET.data = std::max( _info0.data, _info1.data);
            return RET;
        }
        friend ostream& operator<<( ostream & _cout, __Info_max_ const& _info){
            return _cout<< "{"<< _info.data<< "}";
        }
    };
} // namespace ___RMQ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值