一句话总结:二维滑动窗口
看到题目,首先打开标签,看到一个 R M Q RMQ RMQ
第一反应:二维树状数组!
然鹅我并不会二维维护最大最小值。。
第二反应:二维线段树!!
然鹅会超时(实测)(其实是写的太丑了)
第三反应:二维st表!
可行!
但是转眼一看,标签里面还有个单调队列
emmm…(回忆起了一道题)
于是就有了我们的一句话总结:二维滑动窗口
//单调队列板子
register int head=1,tail=0;
for(int i=1;i<=n;i++){//最大
while(head<=tail&&q[tail]>=a[i]) --tail;
q[++tail]=a[i];
pos[tail]=i;
if(pos[head]<=i-m) ++head;
if(i>=m) write(q[head]),putchar(' ');
}
putchar('\n');
head=1,tail=0;
for(int i=1;i<=n;i++){//最小
while(head<=tail&&q[tail]<=a[i]) --tail;
q[++tail]=a[i];
pos[tail]=i;
if(pos[head]<=i-m) ++head;
if(i>=m) write(q[head]),putchar(' ');
}
putchar('\n');
然鹅问题又出来了,等我去翻滑动窗口的记录时,我发现自己是用线段树氵过的。。。(于是就重新学了一遍)
分析:
滑动窗口是在一条直线上,只用一维维护;
而本题需要找二维的正方形,听起来似乎不难,而且实际上也是如此。
我们需要找到一个办法可以把每个 n × n n×n n×n的正方形中的最大值和最小值维护起来;
而第一反应当然就是对行维护一个最大一个最小,再对列维护一个最大一个最小
这样似乎可行,但是怎么统计答案呢?
因为每个行和列数组的最大最小值不一定代表这个正方形的最大和最小
所以在这停顿,换个想法:对行数组再进行一次单调对列!
这个方法明显可行!因为对行数组在纵方向上再进行一次统计,覆盖的范围就变成二维的了
最后统计答案最大数组 n n n到 a a a行, n n n到 b b b列减去答案最小数组对应位置的最小值即可
具体代码
#include<bits/stdc++.h>
#define N 3005
#define inf 0x3f3f3f3f
#define endl '\a'
using namespace std;
int a,b,n,ans=inf;//行数,列数,正方形边长、答案
int mp[N][N];//原数组
int maxn[N][N],minn[N][N];//对每一行处理后的最大最小(以及省空间也拿来当作答案数组了)
int q[N],pos[N]<