算法 {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