[BZOJ1047][HAOI2007]理想的正方形(二维ST表)

传送门


昨晚回宿舍路上Rose_max肉老师做完了这道题问我怎么做,我这么辣鸡怎么可能会做嘛。。
然后我就说:二维线段树模版题(事实上我不会写二维线段树。。)
肉老师听完,淡淡的一笑:“太不优秀了。。”
然后我想啊想,也没有想到除了二维数据结构之外的方法。
然后肉老师又淡淡一笑:“二维ST表”
然后他转身而去,留下一个背影,我在风中惘然。
对啊,二维st表。

哈哈事实上为什么可以用二维st表呢,因为我们发现a,b<=1000并且并没有修改操作,然后他是一个RMQ问题。那么st表不就很优秀吗??不懂st表的同学,可以去看一下hanks_o的博客,二维st表的话就设f[i][j][k]为(i,j)向右向上2^k的正方形的最小最大值,然后更新即可,注意这题如果是长方形就不可做了,因为要开 N 2 l o g 2 N 的空间也就是一个亿啊,会爆的。。

一开始RE了,不知道为什么,后来找hanks_o欧老师来帮我看代码,他把

for(int k=1;(1<<k)<=min(A,B);k++)

改成

for(int k=1;k<=Log[min(A,B)];k++)

就过了???为什么?
AKCqhzdy神犇在评论下已经指出:
因为 ( 1 << k ) 是左移 k 位,那么 k = 1 的时候就等于 2 ,然而 l o g ( 1 ) = 0 .所以应该是 ( 1 << ( k 1 ) )

所以我是sb这点就莓得说了。。。


#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1010;
const int lgn =11;
const int INF =1e9;
int mymax(int a,int b,int c,int d){return max(max(max(a,b),c),d);}
int mymin(int a,int b,int c,int d){return min(min(min(a,b),c),d);}
int mx[maxn][maxn][lgn],mn[maxn][maxn][lgn];
int Log[maxn];
int A,B,n;
void st_pre()
{
    for(int k=1;k<=Log[min(A,B)];k++)
        for(int i=1;i+(1<<k)-1<=A;i++)
            for(int j=1;j+(1<<k)-1<=B;j++)
            {
                mx[i][j][k]=mymax(mx[i][j][k-1],mx[i+(1<<k-1)][j][k-1],mx[i][j+(1<<k-1)][k-1],mx[i+(1<<k-1)][j+(1<<k-1)][k-1]);
                mn[i][j][k]=mymin(mn[i][j][k-1],mn[i+(1<<k-1)][j][k-1],mn[i][j+(1<<k-1)][k-1],mn[i+(1<<k-1)][j+(1<<k-1)][k-1]);
            }   
}
int st_max(int x1,int y1,int x2,int y2)
{
    int k=Log[n];
    return mymax(mx[x1][y1][k],mx[x2-(1<<k)+1][y1][k],mx[x1][y2-(1<<k)+1][k],mx[x2-(1<<k)+1][y2-(1<<k)+1][k]);
}
int st_min(int x1,int y1,int x2,int y2)
{
    int k=Log[n];
    return mymin(mn[x1][y1][k],mn[x2-(1<<k)+1][y1][k],mn[x1][y2-(1<<k)+1][k],mn[x2-(1<<k)+1][y2-(1<<k)+1][k]);
}
int main()
{
    scanf("%d%d%d",&A,&B,&n);
    for(int i=1;i<=A;i++)
        for(int j=1;j<=B;j++)
        {
            int x; scanf("%d",&x);
            mx[i][j][0]=mn[i][j][0]=x;
        }
    Log[1]=0; for(int i=2;i<=max(A,B);i++) Log[i]=Log[i/2]+1;
    st_pre();
    int ans=INF;
    for(int i=1;i+n-1<=A;i++)
        for(int j=1;j+n-1<=B;j++)
            ans=min(ans,st_max(i,j,i+n-1,j+n-1)-st_min(i,j,i+n-1,j+n-1));
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/cabi_zgx/article/details/80027015