目录
介绍
双向队列
单调性的讨论
单调栈
例题
例题讲解
Cow Line
滑动Windows
分析
代码
最大矩形main积
分析
代码
先提前介绍一下一个东西:deque
话说这个东西和list很像啊,只是少了一个插入insert操作罢了……
不过为什么还要创造deque这种东西呢? 原因是,list太慢了……
转回正题,deque的头文件是
#include
#include
using namespace std;
以上两个都可以,但必须要加using namespace std;(bits/stdc++.h瑟瑟发抖)
至于函数……
dequedq;
dq.push_back(1);
dq.push_front(2);
dq.push_front(3);
dq.push_back(4);
// dq : 3 2 1 4
dq.pop_back();
// dq : 3 2 1
dq.pop_front();
// dq : 2 1
这里就针对STL不多说了吧……
单调队列,即单调递减或单调递增的一个队列,不过,它不是一个普通的FIFO队列,而是双向队列。
单调栈,单调递增或单调递减减的栈,跟单调队列差不多,但是只用到它的一端。——百度百科
就这么短,没别的了
直接上模板代码吧
template
struct DownStack{
T sta[1001];
int bck;
inline T front() {
return sta[1];
}
inline T back() {
return sta[bck];
}
inline void pop_back() {
bck--;
}
inline bool empty() {
return bck;
}
inline int size() {
return bck;
}
inline void push_back(T a) {
while(back() ds;
inline void output() {
for(register int i=ds.begin();i
输出结果为
1
1 -1
1 0
可以看出,输出的每一个序列都是单调下降的。单调上升就可以直接类比得出。
忽略单调队列
单纯的模拟题,就不多说了吧
#include
#include
using namespace std;
int read()
{
int a=0,f=1; char c=getchar();
while(c<'0'||c>'9') { if(c=='-') f=-f; c=getchar(); }
while(c>='0'&&c<='9') a=a*10+c-'0',c=getchar();
return a*f;
}
int S=read(),k;
char s[2];
dequedq;
int main()
{
while(S--)
{
scanf("%s",s);
if(s[0]=='A')
{
scanf("%s",s);
if(s[0]=='L') dq.push_front(++k);
else dq.push_back(++k);
}
else
{
scanf("%s",s);
int t=read();
while(t--)
if(s[0]=='L') dq.pop_front();
else dq.pop_back();
}
}
while(!dq.empty())
{
printf("%d\n",dq.front());
dq.pop_front();
}
}
这可不是普通的板题,而是一道十分重要的板题!
我们可以对两种询问分别运用两个不同单调性的队列来维护。
对于最小值而言,就维护一个单调上升的队列;反之,对于最大值而言,就可以维护一个单调下降的队列。
在这种时候,队列的头元素就是要求的最大/最小值。
也许你会问,一直只删除后面的元素,那不是只有pop完了过后才会更改头元素吗?
对,不过,你忘了一件事:窗口的大小为k,只能有k个元素在窗口里。
所以,还要维护开头的下标,如果下标与当前的i的差距超过了k的话,就可以直接pop掉。
当然,推荐用手动模拟双向队列,这样时间复杂度要好一些。就怕某些OJ卡list和deque
同理,为了缩小空间,可以使用同一个队列来进行两种操作,中间记得清空队列,即初始化和头尾均置为初始值。
#include
#include
#define reg register
template
inline T read() {
T a=0; char c=getchar(),f=1;
while(c<'0'||c>'9') {
if(c=='-') f=-f;
if(c==-1) return c;
c=getchar();
}
while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+(c^48),c=getchar();
return a*f;
}
template
inline int write(T x) {
if(x<0) x=(~x)+1, putchar('-');
if(x/10) write(x/10);
return putchar(x%10|48);
}
template
inline int write(T x,char c) {
return write(x)&&putchar(c);
}
template
inline T Max(T a,T b) { return a>b?a:b; }
template
inline T Min(T a,T b) { return a
inline T Abs(T a) { return a<0?-a:a; }
const int MAXN=1000001;
int n=read(),k=read();
struct node{
int it,val;
node(int I=0,int V=0) { it=I,val=V; }
}dq[MAXN];
int fnt,bck;
int a[MAXN];
int main() {
for(reg int i=1;i<=n;i++) {
a[i]=read();
}
memset(dq,0x3f,sizeof dq);
fnt=1; bck=0;
for(reg int i=1;i0&&dq[bck].val>a[i])
bck--;
dq[++bck]=node(i,a[i]);
}
for(reg int i=k;i<=n;i++) {
if(dq[fnt].it+k==i)
fnt++;
while(fnt<=bck&&bck>0&&dq[bck].val>a[i])
bck--;
dq[++bck]=node(i,a[i]);
write(dq[fnt].val);
if(i!=n) putchar(' ');
}
putchar(10);
memset(dq,-0x3f,sizeof dq);
fnt=1; bck=0;
for(reg int i=1;i0&&dq[bck].val0&&dq[bck].val
我们思考一下如果i为子矩阵中高度最小的矩阵
那么i所能构造的最大子矩阵也就是i左边第一个比它矮的
到i右边第一个比它矮的距离再乘上i的高度
那么原题便转换成了(表示左边第一个比它矮的,表示右边第一个比它矮的,表示第个的高度)
所以,对于一个任意的来说,最主要的就是求和了
不过如何求?(都在单调队列和单调栈这个区块上,你觉得还有什么方法)
我们可以维护一个单调递增的栈 ,那么装进时,便需要弹出栈中不符合的元素
对于一个元素来说,入栈的时候,就是。
问题是——怎么求?
——出栈的时候(设当前遍历到的元素为),
原因很简单,当当前元素出栈时,
至于具体处理,用一个结构体储存一下进栈时的即可
#include
#include
#include
#define reg register
typedef long long LL;
template
inline T read() {
T a=0; char c=getchar(),f=1;
while(c<'0'||c>'9') {
if(c=='-') f=-f;
if(c==-1) return c;
c=getchar();
}
while(c>='0'&&c<='9') a=(a<<1)+(a<<3)+(c^48),c=getchar();
return a*f;
}
template
inline int write(T x) {
if(x<0) x=(~x)+1, putchar('-');
if(x/10) write(x/10);
return putchar(x%10|48);
}
template
inline int write(T x,char c) {
return write(x)&&putchar(c);
}
template
inline T Max(T a,T b) { return a>b?a:b; }
template
inline T Min(T a,T b) { return a
inline T Abs(T a) { return a<0?-a:a; }
LL n;
LL h[100002];
struct node{
LL val,id;
node(){}
node(LL V,LL ID) { val=V; id=ID; }
};
LL maxn;
LL l[100002],r[100002];
node sta[100002]={};
int top;
inline void solve() {
top=0;
maxn=-0x3f3f3f3f;
memset(l,0,sizeof l); memset(r,0,sizeof r);
for(reg int i=1;i<=n;i++) h[i]=read();
h[n+1]=0;
for(reg int i=1;i<=n+1;i++) {
while(top) {
node t=sta[top];
if(t.val())&&n!=-1) {
solve();
}
}