单调队列和单调栈
一 单调队列
1.定义
单调队列是一种数据结构,用于存储的是在一个区间内的最大值,通常用于区间查询
2 实现方式
下面以存储最小值的单调队列为例,假设我们的区间范围是为n,那么在单调队列中,我们先不断的出队,去掉那些已经过时的元素,然后在让最新的元素从队尾进队,不断删除那些比它时间长并且比它还小的数
3 Example
假设现在用8个数要进入队列,求三个数长度的区间内的最小值
进队 | 单调队列 | 操作 |
---|---|---|
3 | 3 | 3入队 |
1 | 1 | 1干掉3 |
2 | 1 2 | 2入队 |
5 | 1 2 5 | 5入队 |
9 | 2 5 9 | 1超时出队,9入队 |
6 | 5 6 | 9被6取代 |
7 | 6 7 | 5出队,7入队 |
1 | 1 | 1干掉所有 |
4 代码实现
struct dull_queue
{
int bottom;
int top;
int cnt;
int length;
struct elem
{
int value;
int time;
}elem[100];
// top is the small one
void Getin(int x)
{
struct elem temp;
temp.time = cnt++;
temp.value = x;
while(bottom<=top&&elem[bottom].time+length<=cnt) bottom++;
// 删除最早进入的一批
while(bottom<=top&&temp.value<elem[top].value) top--;
// 向队列里面加人
elem[++top] = temp;
}
int Min()
{
return elem[bottom].value;
}
// 得到最小值
void init()
{
bottom = 1;
top = 0;
cnt = 0;
}
// 初始化
}Small_queue;
5 单调队列模版题
其实这道题也可以使用单调队列进行解决,按照题意我们要找的其实就是 m a x ( f [ i − r ] f [ i − l ] ) max(f[i-r]~f[i-l]) max(f[i−r] f[i−l]),区间的长度为 r − l + 1 r- l+1 r−l+1求区间内的最大值,只是这个区间相对于取值其实是有有个l的延迟,所以从i = L开始进行循环。在这道题里面有一些点是我们无法取到。针对这个情况我们去把f数组中的数初始化为一个极小值,如果他前面的数有正常值,那么他才能得到一只正常值,所以我们将 f [ 0 ] = 0 f[0] = 0 f[0]=0.
#include<iostream>
#include <string.h>
#define N 3001000
using namespace std;
int n,l,r;
int a[N];
int q[N];
int f[N];
int ans;
int main()
{
int top = 1;
int bottom = 1;
scanf("%d%d%d",&n,&l,&r);
for (int i = 0; i <= n; i++) scanf("%d",&a[i]);
memset(f, 0xcf, sizeof(f));
ans = f[0];
int cnt = 0;
f[cnt] = 0;
for (int i = l; i <= n ; i++)
{
while(top<=bottom&& q[top] + r < i) top++;
// 如果已经超时,那么将它退队
while(top<=bottom&&f[cnt] >= f[q[bottom]]) bottom--;
// 如果这个数比它大,那么从队尾到队首不断清理对手
q[++bottom] = cnt;
// 让他进入这个单调队列
f[i] = f[q[top]] + a[i];
// 得到f[i]这一点的数值
cnt++;
}
for (int i = n - r + 1; i <= n; i++) ans = max(ans,f[i]);
printf("%d",ans);
}