1047: [HAOI2007]理想的正方形——二维单调队列

http://www.lydsy.com/JudgeOnline/problem.php?id=1047

对每一行维护一个单调队列,保存在lmin[][],lmax[][]

然后对每一列维护一个单调队列,最后n*n枚举

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define clr(a,b) memset(a,b,sizeof(a))
const int maxn = 1100;
const int INF = 0x3f3f3f3f;
using namespace std;
int n,m,k;
int que[maxn],a[maxn][maxn];
int lmin[maxn][maxn],lmax[maxn][maxn];
int rmin[maxn][maxn],rmax[maxn][maxn];
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
    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]);
        }
    }
    int front,rear;
    for(int i=1;i<=n;++i){
        front=rear=1;
        for(int j=1;j<=m;++j){
            while(front<rear&&a[i][que[rear-1]]>a[i][j]) rear--;
            que[rear++]=j;
            while(front<rear&&j-que[front]+1>k) front++;
            if(j>=k) lmin[i][j-k+1]=a[i][que[front]];

        }
        front=rear=1;
        for(int j=1;j<=m;++j){
            while(front<rear&&a[i][que[rear-1]]<a[i][j]) rear--;
            que[rear++]=j;
            while(front<rear&&j-que[front]+1>k) front++;
            if(j>=k) lmax[i][j-k+1]=a[i][que[front]];
        }
    }
    for(int j=1;j<=m-k+1;++j){//列
        front=rear=1;
        for(int i=1;i<=n;++i){//行
            while(front<rear&&lmin[que[rear-1]][j]>lmin[i][j]) rear--;
            que[rear++]=i;
            while(front<rear&&i-que[front]+1>k) front++;
            if(i>=k) rmin[j][i-k+1]=lmin[que[front]][j];
        }
        front=rear=1;
        for(int i=1;i<=n;++i){
            while(front<rear&&lmax[que[rear-1]][j]<lmax[i][j]) rear--;
            que[rear++]=i;
            while(front<rear&&i-que[front]+1>k) front++;
            if(i>=k) rmax[j][i-k+1]=lmax[que[front]][j];
        }
    }
    int ans=INF;
    for(int i=1;i<=m-k+1;++i){
        for(int j=1;j<=n-k+1;++j){
            if(rmax[i][j]!=-1)
            ans=min(ans,rmax[i][j]-rmin[i][j]);
        }
    }
    printf("%d\n",ans);
    return 0;
}
时间: 2024-07-28 19:35:55

1047: [HAOI2007]理想的正方形——二维单调队列的相关文章

【bzoj1047】[HAOI2007]理想的正方形 二维RMQ

题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000 输出 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. 样例输入 5 4 2 1 2 5 6 0 1

【二维单调队列】BZOJ1047-[HAOI2007]理想的正方形

[题目大意] 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. [思路] 裸的二维单调队列.二维单调队列的思路其实很简单: (1)对于每一行维护两个宽度为n的滑动窗口记录单行中的min和max,和POJ2823一个道理.此时相当于把n个格子浓缩到了一个格子当中. (2)维护n*n大小的二维滑动窗口中的min和max.由于有了第一步操作,只要考虑每一个n*n的矩形右上角到右下角的最值即可.相当于对于每一列,维护两个宽度为n的滑动窗口.

1047: [HAOI2007]理想的正方形

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4075  Solved: 2277[Submit][Status][Discuss] Description 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. Input 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=

[BZOJ 1047][HAOI 2007]理想的正方形(二维滑动窗口+单调队列)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1047 思路:裸的二维上的滑动窗口问题,可以借鉴一维滑动窗口的思路.首先预处理出每一列j的.以第i行元素为结尾.长度为n的区间的最大值maxv[i][j].最小值minv[i][j],然后再搞每一行,求出以每一行i结尾.行标上长度为n的区间.以第j列结尾.列标上长度为n的区间得到的二维区间最大值与最小值之差,遍历每一行得到这个差的最小值即为答案. #include <iostrea

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

[luoguP2216] [HAOI2007]理想的正方形(二维单调队列)

传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 1 #include <cstdio> 2 #include <iostream> 3 4 using namespace std; 5 6 const int MAXN = 1001; 7 int a, b, n, h, t; 8 long long c[MAXN][MAXN], q[MAXN], m

bzoj 1047: [HAOI2007]理想的正方形【单调队列】

没有复杂结构甚至不长但是写起来就很想死的代码类型 原理非常简单,就是用先用单调队列处理出mn1[i][j]表示i行的j到j+k-1列的最小值,mx1[i][j]表示i行的j到j+k-1列的最大值 然后就变成求单列最大最小值,用上面同样的方法处理出对于列的mn2mx2即可 #include<iostream> #include<cstdio> using namespace std; const int N=1005; int n,m,k,a[N][N],mn1[N][N],mx1[

BZOJ 1047 [HAOI2007]理想的正方形

[看了题解才会做 这是一个典型的二维滑动窗口问题~ 二维滑动窗口问题的处理方法可以类比一维滑动窗口的处理方法 首先将矩阵分解成B个列,对这B个列分别用单调队列维护一个长度为N的一维滑动窗口.记录colmax[i][j]为第j列第i行的元素(即第j个列的第i个元素)到第j列第i-N+1的元素(即第j个列的第i-N+1个元素)的最大值.这个用单调队列随便维护一下就好啦~ 然后将矩阵分解成A个行,对这A个行再分别用单调队列维护一个长度为N的一维滑动窗口.记录rowmax[i][j]为colmax[i]

BZOJ 1047 HAOI2007 理想的正方形 单调队列

题目大意:给定一个a*b的矩阵,求一个n*n的子矩阵,使矩阵中的最大值与最小值之差最小 对于每行维护一个单调递减的队列.再弄一个竖着的队列.维护n个格子之内的最大值就可以 两遍统计出最大值和最小值 然后得到ans就可以 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 1010 using namespace std; struct abcd