[题解](单调队列)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); }