[题解](单调队列)luogu_P2216_BZOJ_1047 理想的正方形

调了半天,发现这个写法确实极易错......

对于每列都维护一个单调队列记录最大最小值,这样一次操作后就把最大最小值压到了一维,

然后再对这一行维护一个单调队列,每次更新ans值,然而对于数组和队列下标的访问极易搞错

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=1010;
int n,m,k,ans=0x7fffffff,a[maxn][maxn];
deque<int>ymax[maxn],ymin[maxn],xmax,xmin;
int abs(int a){return a>0?a:-a;}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
    scanf("%d",&a[i][j]);
    
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            while(!ymax[j].empty() && a[ymax[j].back()][j]<a[i][j])ymax[j].pop_back();
            while(!ymax[j].empty() && ymax[j].front()+k<=i)ymax[j].pop_front();
            ymax[j].push_back(i);
        }
        for(int j=1;j<=m;j++){
            while(!ymin[j].empty() && a[ymin[j].back()][j]>a[i][j])ymin[j].pop_back();
            while(!ymin[j].empty() && ymin[j].front()+k<=i)ymin[j].pop_front();
            ymin[j].push_back(i);
        }
        if(i<k)continue;//还不能成为正方形就先跳过 
        //此时已压成一行,滑动窗口即可 
        xmin.clear();xmax.clear();//不能忘了初始化 
        for(int j=1;j<=m;j++){
            while(!xmax.empty() && a[ymax[xmax.back()].front()][xmax.back()]<a[ymax[j].front()][j])xmax.pop_back();
            while(!xmax.empty() && xmax.front()+k<=j)xmax.pop_front();
            xmax.push_back(j);
            while(!xmin.empty() && a[ymin[xmin.back()].front()][xmin.back()]>a[ymin[j].front()][j])xmin.pop_back();
            while(!xmin.empty() && xmin.front()+k<=j)xmin.pop_front();
            xmin.push_back(j);
            if(j<k)continue;
            ans=min(ans,abs(a[ymin[xmin.front()].front()][xmin.front()]-a[ymax[xmax.front()].front()][xmax.front()]));
        }
    }
    printf("%d\n",ans);
}

 

posted @ 2019-04-07 18:59  羊肉汤泡煎饼  阅读(127)  评论(0编辑  收藏  举报