倍增+ST表

倍增

任意一个数可以由二进制表示,如31 = 2^0 + 2^1+ 2^2 + 2^3 + 2^4,且最少是由这五个数表示的。 倍增就是说用最少的步骤(五个数字)得到最大的范围(31)的思想。 这与二分是相反的。

ST表

基于倍增思想实现的区间最值查询优化方法。

预处理O(nlogn),查询O(1)。

这里以查询最大值为例。

先开一个二维的数组 st[n][n],st[i][j] 代表从第 i 位开始,len=2^j 的区间的最大值。

第 0 列用来记录这个数组。(其实也可以用来表示len=2^0=1的区间的最值,即本身)

后续记录最值都是查询上一列的目标区间段的最值,需要用到dp。

st[i][j]表示从第 i 位开始,len=2^j 的区间的最大值,不难发现st[i][j]只能为len=2^(j-1)的相邻两个区间的最大值,即:

dp[i][j] = max(dp[i][j-1], dp[i+1<<(j-1)][j-1])

以此构建ST表

vector<vector<ll>> st(N, vector<ll>(N));

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int n;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>st[i][0];
    for(int j=1;j<=log2(n);j++)
    {
        for(int i=1;i<=n-(1<<j);i++)
        {
            st[i][j]=max(st[i][j-1], st[i+(1<<(j-1))][j-1]);
        }
    }
    return 0;
}

查询便是dp,[l, r]的最小值位覆盖住[l, r]的两个小区间的最小值。

这里用log2(l-r+1),一是两个log2(len)可以覆盖住区间,二是由于倍增的缘故,log2(len)套用ST表可以很快得出对应的最值,复杂度为O(1)。

int query(int l, int r)
{
    int j=log2(r-l+1);
    return max(st[l][j], st[r-(1<<j)+1][j]);
}

查询最小值只用将max换为min即可

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务