谈一类易实现的非四毛子线性 RMQ

考虑设 \(B=64\),每 \(64\) 个元素分一块。

处理跨块查询

这样的查询,是由一段的后缀拼上若干整块拼上一段前缀。

因此我们维护每个块的前后缀最值以及将每一块的最值拿出建立 \(ST\) 表。

复杂度 \(O(n+\frac{n}{B}\log\frac{n}{B})=O(n)\)

处理单块查询

这也是为什么 \(B=64\)

考虑对每一块从左往右做单调栈,那么询问 \([l,r]\),等价于询问以 \(r\) 作为右端点时,单调栈内下标 \(\ge l\) 的最小值。

因为 \(B=64\),用一个 unsigned long long 即可保存单调栈状态。

查询时,我们先通过位运算将 \(<l\) 的位置为零,然后查询最低位即可。

示例代码:

namespace ST{
    int pre[N],suf[N],st[14][N/B],sz,lg[N];
    ull sta[N];
    int Sta[65],top;
    void init(){
        lg[0]=-1;
        for(int i=1;i<=n;++i)lg[i]=lg[i>>1]+1;
        for(int i=0;i<n;++i){
            if(i&63)pre[i]=max(pre[i-1],a[i]);
            else pre[i]=a[i];
        }
        for(int i=n-1;~i;--i){
            if(i==n-1||(i+1&63)==0)suf[i]=a[i];
            else suf[i]=max(suf[i+1],a[i]);
            if(!(i&63))st[0][i>>6]=suf[i];
        }
        sz=(n-1>>6)+1;
        for(int j=1;(1<<j)<=sz;++j)for(int i=0;i<=sz-(1<<j);++i)st[j][i]=max(st[j-1][i],st[j-1][i+(1<<j-1)]);
        for(int i=0,h=0;i<n;++i){
            if((i&63)==0){
                sta[i]=1ull;h=i;Sta[top=1]=i;continue;
            }
            sta[i]=sta[i-1];
            while(top&&a[Sta[top]]<a[i]){
                sta[i]^=1ull<<Sta[top]-h;--top;
            }
            sta[i]|=1ull<<i-h;Sta[++top]=i;
        }
    }
    int get(int l,int r){
        if(l>r)return 0;
        int k=lg[r-l+1];
        return max(st[k][l],st[k][r-(1<<k)+1]);
    }
    int ask(int l,int r){
        if((l>>6)!=(r>>6)){
            return max({suf[l],pre[r],get((l>>6)+1,(r>>6)-1)});
        }
        int h=(r>>6)<<6;
        return a[l+__builtin_ctzll(sta[r]>>(l-h))];
    }
}
posted @ 2025-10-12 17:13  spdarkle  阅读(5)  评论(1)    收藏  举报