rmq_ST模板

某线段最值:
/*  rmq:
 ST:
    minn[i][j]表示从第i个到i+(1<<j)-1的最小值
    状态方程:minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1])
    查询[l,r]区间时,区间个数是r-l+1,k为log2(r-l+1),那么最小值为minn[l][k],
    因为log2(r-l+1)可能存在一点误差,即判断一下后端点
    即min(minn[l][k],minn[r-(1<<k)+1][k])
    最大值:
        同理
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=1e5+7;
int minn[N][21],maxx[N][21],n;
int Log2[N];//表示log2(i)
void ST()
{
    for(int i = 0; i <= n; i ++)Log2[i] = (i == 0 ? -1 : Log2[i >> 1] + 1);
    for(int j=1;j<21;j++)
        for(int i=1;i+(1<<j)<=n+1;i++)
        {
            minn[i][j]=min(minn[i][j-1],minn[i+(1<<(j-1))][j-1]);
            maxx[i][j]=max(maxx[i][j-1],maxx[i+(1<<(j-1))][j-1]);
        }
}
int query_min(int l,int r)
{
    int k=Log2[r-l+1];
    return min(minn[l][k],minn[r-(1<<k)+1][k]);
}
int query_max(int l,int r)
{
    int k=Log2[r-l+1];
    return max(maxx[l][k],maxx[r-(1<<k)+1][k]);
}
int main()
{
    int q;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&minn[i][0]);
        maxx[i][0]=minn[i][0];
    }
    ST();
    while(q--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%d\n",query_max(l,r)-query_min(l,r));
    }
    return 0;
}

某矩阵最值

 

/*
    二维的rmq可以将每一行看作是一维的rmq
    maxx[i][j][k]表示: 第i行 [j,j+(1<<k)-1] 区间中的最大值
    maxx[i][j][k]=max(maxx[i][j][k-1],maxx[i][j+(1<<(k-1))][k-1]);
    该时间复杂度为:
        建表:0(n*m*log(m))
        查询:0(n)
*/
#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int N=1e3+7;
const int inf=1e9+7;
int n,m;
int maxx[N][N][13],minn[N][N][13];
int Log2[N];
void ST()
{
    for(int i = 0; i <= m; i ++)Log2[i] = (i == 0 ? -1 : Log2[i >> 1] + 1);
    for(int i=1;i<=n;i++)
        for(int k=1;k<13;k++)
            for(int j=1;j+(1<<k)<=m+1;j++)
            {
                maxx[i][j][k]=max(maxx[i][j][k-1],maxx[i][j+(1<<(k-1))][k-1]);
                minn[i][j][k]=min(minn[i][j][k-1],minn[i][j+(1<<(k-1))][k-1]);
            }
}
int query_min(int lx,int ly,int rx,int ry)
{
    int k=Log2[ry-ly+1];
    int minn1=inf;
    for(int i=lx;i<=rx;i++)
        minn1=min(minn1,min(minn[i][ly][k],minn[i][ry-(1<<k)+1][k]));
    return minn1;
}
int query_max(int lx,int ly,int rx,int ry)
{
    int k=Log2[ry-ly+1];
    int maxx1=-inf;
    for(int i=lx;i<=rx;i++)
        maxx1=max(maxx1,max(maxx[i][ly][k],maxx[i][ry-(1<<k)+1][k]));
    return maxx1;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            scanf("%d",&maxx[i][j][0]);
            minn[i][j][0]=maxx[i][j][0];
        }
    ST();
    int q;
    scanf("%d",&q);
    while(q--)
    {
        int lx,ly,rx,ry;
        scanf("%d%d%d%d",&lx,&ly,&rx,&ry);
        printf("%d %d\n",query_max(lx,ly,rx,ry),query_min(lx,ly,rx,ry));
    }
    return 0;
}

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值