【题目大意】

有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小。

【思路】

裸的二维单调队列。二维单调队列的思路其实很简单:

(1)对于每一行维护两个宽度为n的滑动窗口记录单行中的min和max,和POJ2823一个道理。此时相当于把n个格子浓缩到了一个格子当中。

(2)维护n*n大小的二维滑动窗口中的min和max。由于有了第一步操作,只要考虑每一个n*n的矩形右上角到右下角的最值即可。相当于对于每一列,维护两个宽度为n的滑动窗口。此时循环要行和列里外颠倒,而列只要从第n列开始维护即可(我一开始就错在了这两个地方)

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define INF 0x7fffffff
struct node
{
int data,pos;
};
using namespace std;
const int MAXN=+;
int a,b,n;
int num[MAXN][MAXN];
int rmin[MAXN][MAXN],rmax[MAXN][MAXN],smin[MAXN][MAXN],smax[MAXN][MAXN]; void init()
{
scanf("%d%d%d",&a,&b,&n);
for (int i=;i<a;i++)
for (int j=;j<b;j++) scanf("%d",&num[i][j]);
} void humdrum_queue()
{
/*对于每一行,用单调队列维护[x-n+1,x]的最小值和最大值*/
for (int i=;i<a;i++)
{
int minhead=,mintail=,maxhead=,maxtail=;
node qmin[MAXN],qmax[MAXN];
for (int j=;j<b;j++)
{
int nown=num[i][j];
/*维护最小值*/
while (minhead<mintail && qmin[mintail-].data>nown) mintail--;
qmin[mintail++]=(node){nown,j};
while (minhead<mintail && qmin[minhead].pos<=j-n) minhead++;
rmin[i][j]=qmin[minhead].data; /*维护最大值*/
while (maxhead<maxtail && qmax[maxtail-].data<nown) maxtail--;
qmax[maxtail++]=(node){nown,j};
while (maxhead<maxtail && qmax[maxhead].pos<=j-n) maxhead++;
rmax[i][j]=qmax[maxhead].data;
}
} /*对于以[i,j]为右下角的n*n矩形,用单调队列维护它的最小值和最大值
这步操作可以用单调队列维护每一列,相当于维护该矩形右上角到右下角对应点的rmin与rmax值*/
/*|ATTENTION|要注意的是这里i和j要颠倒过来,所以内外循环以及队列中的pos均要颠倒!*/
for (int j=n-;j<b;j++)
{
int minhead=,mintail=,maxhead=,maxtail=;
node qmin[MAXN],qmax[MAXN];
for (int i=;i<a;i++)
{
int nowmin=rmin[i][j],nowmax=rmax[i][j];
/*维护最小值*/
while (minhead<mintail && qmin[mintail-].data>nowmin) mintail--;
qmin[mintail++]=(node){nowmin,i};
while (minhead<mintail && qmin[minhead].pos<=i-n) minhead++;
smin[i][j]=qmin[minhead].data; /*维护最大值*/
while (maxhead<maxtail && qmax[maxtail-].data<nowmax) maxtail--;
qmax[maxtail++]=(node){nowmax,i};
while (maxhead<maxtail && qmax[maxhead].pos<=i-n) maxhead++;
smax[i][j]=qmax[maxhead].data;
}
}
} void getans()
{
int ans=INF;
for (int i=n-;i<a;i++)
for (int j=n-;j<b;j++)
if (smax[i][j]-smin[i][j]<ans) ans=smax[i][j]-smin[i][j];
cout<<ans<<endl;
} int main()
{
init();
humdrum_queue();
getans();
return ;
}

【二维单调队列】BZOJ1047-[HAOI2007]理想的正方形的更多相关文章

  1. bzoj1047-理想的正方形(二维单调队列)

    题意: 给一个矩阵,给出行列和每个数,再给出一个N,求出所有N*N的子矩阵中最大值最小值之差的最小值解析: 暴力枚举肯定不行,这题可以用二维单调队列做,把同一行的连续N个点缩成一个点保存最大最小值预处 ...

  2. BZOJ1047: [HAOI2007]理想的正方形 [单调队列]

    1047: [HAOI2007]理想的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2857  Solved: 1560[Submit][St ...

  3. bzoj千题计划215:bzoj1047: [HAOI2007]理想的正方形

    http://www.lydsy.com/JudgeOnline/problem.php?id=1047 先用单调队列求出每横着n个最大值 再在里面用单调队列求出每竖着n个的最大值 这样一个位置就代表 ...

  4. [BZOJ1047][HAOI2007]理想的正方形 二维单调队列

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 我们对每矩阵的一列维护一个大小为$n$的单调队列,队中元素为矩阵中元素.然后扫描每一 ...

  5. bzoj1047 [HAOI2007]理想的正方形——二维单调队列

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1047 就是先对行做一遍单调队列,再对那个结果按列做一遍单调队列即可. 代码如下: #incl ...

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

    传送门 1.先弄个单调队列求出每一行的区间为n的最大值最小值. 2.然后再搞个单调队列求1所求出的结果的区间为n的最大值最小值 3.最后扫一遍就行 懒得画图,自己体会吧. ——代码 #include ...

  7. [bzoj1047][HAOI2007]理想的正方形_动态规划_单调队列

    理想的正方形 bzoj-1047 HAOI-2007 题目大意:有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 注释:$2\le a, ...

  8. BZOJ1047[HAOI2007]理想的正方形——二维ST表

    题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非 ...

  9. 【单调队列】bzoj1047 [HAOI2007]理想的正方形

    先把整个矩阵处理成b[n][m-K+1].c[n][m-K+1]大小的两个矩阵,分别存储每行每K个数中的最大.最小值,然后再通过b.c处理出d.e分别表示K*K大小的子矩阵中的最大.最小值即可.单调队 ...

随机推荐

  1. nginx压力测试和优化配置

    115 yum -y install gcc automake autoconf libtool make 116 yum install ctags 117 mkdir -m 644 -p /usr ...

  2. VC++使用CImage PNG转BMP图片透明背景处理

    PNG格式的图片是支持透明通道的,BMP格式的图片是没有透明通道的,所以当PNG格式的图片转换为BMP格式时,对于PNG图片的透明背景就需要进行特别的处理. VC++中的HBITMAP是支持透明色的, ...

  3. 2、Distributed Optimization

    一.目录: Distributed dynamic programming (as applied to path-planning problems). Distributed solutions ...

  4. 记另类Request method 'GET' not supported

    一般遇到Request method 'GET' not supported这种问题,大家都会找相应controller下的具体方法,把get改为post之类.但是我这次是在访问静态资源,static ...

  5. C++中的垃圾回收和内存管理(续)

    boost memory的gc_allocator的使用 首先编译生成boost-memory的库,由于生成的是.so的动态库,所以需要在运行程序之前,将库文件的路径添加到LD_LIBRARY_PAT ...

  6. codeforces B. Okabe and Banana Trees 结论题

    题目传送门 这道题 枚举一波y就好了 要求x,y整数 所以y最多1000个 然后算一波答案更新就好了 233 #include<cstdio> #include<cstring> ...

  7. [POJ1144][BZOJ2730]tarjan求割点

    求割点 一种显然的n^2做法: 枚举每个点,去掉该点连出的边,然后判断整个图是否联通 用tarjan求割点: 分情况讨论 如果是root的话,其为割点当且仅当下方有两棵及以上的子树 其他情况 设当前节 ...

  8. react+redux基础用法

    在学react的是,发现一旦我们封装好了我们的组件,那么我们的项目就跟搭积木一样简单快速,可是我们发现了一个问题,在一个页面往往会嵌套很多的组件,子组件必须要通过父组件传递参数才能渲染出数据,我们回想 ...

  9. phpcms v9 后台添加修改页面空白页问题解决方法

    phpcms v9 添加修改页面空白页的解决方法 找一个正常运行的phpcms 将caches\caches_model\caches_data 目录下的 content_form.class.php ...

  10. 创建堆 HeapCreate

    创建额外的堆的原因1.对组件进行保护2.更有效的内存管理3.局部访问4.避免线程同步开销5.快速释放 HeapCreate函数原型:HANDLE WINAPI HeapCreate( _In_ DWO ...