二维st表,一种暴力但却快速的二维RMQ利器

先上例题:[HAOI2007]理想的正方形 大部分人都用单调队列,但我不会。首先我们可以暴力枚举所有的可能的正方形,每次我们需要查询RMQ,如果用朴素的方法总复杂度就会变成N^4,你不T谁T

那怎么办,总不可能写正解吧,我们可以用二维st表,预处理N^2logN,每次O(1)查询,N^2水过。

二维st表原理就是将一个正方形分成了4份:
令 st[i][j][k]表示左上角为i,j,边长为k的正方形中的最大值。
sta[i][j][k]=Max(sta[i][j][k-1],sta[i+(1<<k-1)][j][k-1],sta[i][j+(1<<k-1)][k-1],sta[i+(1<<k-1)][j+(1<<k-1)][k-1]);

i,j,k-1:就是左上角那块正方形,i+(1<<k-1),j,k-1,就是左下角那块正方形,剩下两块就是另外两个
查询同理,将代码放到编译器中食用更佳

注意,强制类型转换要用大括号括起要转换的东西,例如 (int)(log(n)/log(2));

Code:

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
#define zmd main
int a,b,n;
int sta[1026][1026][12],sti[1026][1026][12];
int kk;
inline int query1(int x,int y,int xx,int yy)
{
    int t1=sta[x][y][kk],t2=sta[xx-(1<<kk)+1][y][kk],t3=sta[x][yy-(1<<kk)+1][kk],t4=sta[xx-(1<<kk)+1][yy-(1<<kk)+1][kk];
    return max(max(max(t1,t2),t3),t4);
}
inline int query2(int x,int y,int xx,int yy)
{
    int t1=sti[x][y][kk],t2=sti[xx-(1<<kk)+1][y][kk],t3=sti[x][yy-(1<<kk)+1][kk],t4=sti[xx-(1<<kk)+1][yy-(1<<kk)+1][kk];
    return min(min(min(t1,t2),t3),t4);
}
inline int Max(int a,int b,int c,int d)
{
    return max(max(max(a,b),c),d);
}
inline int Min(int a,int b,int c,int d)
{
    return min(min(min(a,b),c),d);
}
int zmd()
{
    std::cin>>a>>b>>n;
    for (int i=1;i<=a;++i) for (int j=1,tmp;j<=b;++j) {scanf("%d",&tmp);sta[i][j][0]=sti[i][j][0]=tmp;}
    int shit=min(a,b);
    for (int k=1;k<=11;++k)
        for (int i=1;i+(1<<k)-1<=a;++i)
            for (int j=1;j+(1<<k)-1<=b;++j)
            {
                sta[i][j][k]=Max(sta[i][j][k-1],sta[i+(1<<k-1)][j][k-1],sta[i][j+(1<<k-1)][k-1],sta[i+(1<<k-1)][j+(1<<k-1)][k-1]);
                sti[i][j][k]=Min(sti[i][j][k-1],sti[i+(1<<k-1)][j][k-1],sti[i][j+(1<<k-1)][k-1],sti[i+(1<<k-1)][j+(1<<k-1)][k-1]);
            }
    kk=(int)(log(n)/log(2));
    int ans=0x3f3f3f3f;
    for (int i=1;i+n-1<=a;i++)
    for (int j=1;j+n-1<=b;j++)
        ans=std::min(ans,query1(i,j,i+n-1,j+n-1)-query2(i,j,i+n-1,j+n-1));
    cout<<ans;
    return 0;
}

转载于:https://www.cnblogs.com/bullshit/p/9583359.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值