poj2823 Sliding Window 单调队列

Sliding Window

Description

An array of size n ≤ 106 is given to you. There is a sliding window of sizek which is moving from the very left of the array to the very right. You can only see thek numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example:
The array is [1 3 -1 -3 5 3 6 7], and k is 3.

Window positionMinimum valueMaximum value
[1  3  -1] -3  5  3  6  7 -13
 1 [3  -1  -3] 5  3  6  7 -33
 1  3 [-1  -3  5] 3  6  7 -35
 1  3  -1 [-3  5  3] 6  7 -35
 1  3  -1  -3 [5  3  6] 7 36
 1  3  -1  -3  5 [3  6  7]37

Your task is to determine the maximum and minimum values in the sliding window at each position.

Input

The input consists of two lines. The first line contains two integersn and k which are the lengths of the array and the sliding window. There aren integers in the second line.

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values.

Sample Input

8 3
1 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7


题目大意

求一段区间内的最小值和最大值


解题思路

单调队列的简单应用

单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。
单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。 

一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值:
1. 在原数列中的位置(下标)
2. 他在动态规划中的状态值
而单调队列则保证这两个值同时单调。

我们维护这样一个队列:队列中的每个元素有两个域{position,value},分别代表他在原队列中的位置和数值 ,我们随时保持这个队列中的元素两个域都单调递增。
那计算的时候,只要在队首不断删除,直到队首的 position 大于等于i-m+1 ,那此时队首元素的值必定是不二人选,因为队列是单调的!
我们看看怎样将 a[i]插入到队列中:首先,要保证 position 单调递增,由于我们动态规划的过程总是从1-n的(反之亦然),所以能保证position的单调增。又因为要保证队列的 value 单调递增,所以将队尾元素不断删除,直到队尾元素小于 a[i],然后将a[i]入队。

代码

#include<cstdio>
#include<iostream>
#include<deque>
using namespace std;

struct node
{
    int p;
    int val;
}a[1000010];
int mmax[1000010];
int mmin[1000010];
deque <node> q1,q2;

int main()
{
    int i,j,k,n;
    scanf("%d%d",&n,&k);
    for(i=1;i<=n;++i)
    {
        scanf("%d",&a[i].val);
        a[i].p=i;
    }
//处理最小
    for(i=1;i<=n;++i)
    {
        while(!q1.empty())
        {
            if(q1.back().val > a[i].val) q1.pop_back();
            else break;
        }
        q1.push_back(a[i]);
        while(!q1.empty())
        {
            if(q1.front().p<i-k+1) q1.pop_front();
            else break;
        }
        mmin[i]=q1.front().val;
    }
//处理最大
    for(i=1;i<=n;++i)
    {
        while(!q2.empty())
        {
            if(q2.back().val < a[i].val) q2.pop_back();
            else break;
        }
        q2.push_back(a[i]);
        while(!q2.empty())
        {
            if(q2.front().p<i-k+1) q2.pop_front();
            else break;
        }
        mmax[i]=q2.front().val;
    }
    //处理输出
    for(i=k;i<n;++i)
    {
        printf("%d ",mmin[i]);
    }
    printf("%d\n",mmin[n]);
    for(i=k;i<n;++i)
    {
        printf("%d ",mmax[i]);
    }
    printf("%d\n",mmax[n]);
    return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值