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;
}
posted @ 2019-01-27 15:27  AKMer  阅读(123)  评论(0编辑  收藏  举报