BZOJ1047:[HAOI2007]理想的正方形
浅谈队列:https://www.cnblogs.com/AKMer/p/10314965.html
题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=1047
对于每一行用单调不增和单调不减队列分别维护最小值和最大值。
对于列,也用单调不增和单调不减队列分别维护最小值和最大值。
步骤如下:
\(1\)、每一行分别把前\(n\)个数的单调队列建好。
\(2\)、取出每一行队头的元素用列的单调队列维护并更新答案。
\(3\)、把每一行在\([2,n+1]\)的元素用单调队列维护好,依次类推,直到\([b-n+1,b]\)的答案被统计完。
时间复杂度:\(O(ab)\)
空间复杂度:\(O(ab)\)
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn=1005;
int list1[maxn],list2[maxn];
int a,b,n,head1,tail1,head2,tail2,ans=2e9;
int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Queue_mn {
int head,tail;
int list[maxn],a[maxn];
void ins(int id) {
while(head!=tail&&a[list[tail-1]]>a[id])tail--;
while(head!=tail&&id-list[head]>=n)head++;list[tail++]=id;
}
int front() {
return a[list[head]];
}
}Mn[maxn];
struct Queue_mx {
int head,tail;
int list[maxn],a[maxn];
void ins(int id) {
while(head!=tail&&a[list[tail-1]]<a[id])tail--;
while(head!=tail&&id-list[head]>=n)head++;list[tail++]=id;
}
int front() {
return a[list[head]];
}
}Mx[maxn];
int main() {
a=read(),b=read(),n=read();
for(int i=1;i<=a;i++)
for(int j=1;j<=b;j++)
Mn[i].a[j]=Mx[i].a[j]=read();
for(int i=1;i<=a;i++)
for(int j=1;j<n;j++)
Mn[i].ins(j),Mx[i].ins(j);
for(int i=n;i<=b;i++) {
for(int j=1;j<=a;j++)
Mn[j].ins(i),Mx[j].ins(i);
head1=tail1=head2=tail2=0;
for(int j=1;j<=a;j++) {
int mn=Mn[j].front(),mx=Mx[j].front();
while(head1!=tail1&&Mn[list1[tail1-1]].front()>mn)tail1--;
while(head1!=tail1&&j-list1[head1]>=n)head1++;list1[tail1++]=j;
while(head2!=tail2&&Mx[list2[tail2-1]].front()<mx)tail2--;
while(head2!=tail2&&j-list2[head2]>=n)head2++;list2[tail2++]=j;
if(j>=n)ans=min(ans,Mx[list2[head2]].front()-Mn[list1[head1]].front());
}
}
printf("%d\n",ans);
return 0;
}