【t019】window(单调队列)

Time Limit: 2 second
Memory Limit: 256 MB

【问题描述】

给你一个长度为N 的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:

Window position Min value Max value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7

你的任务是找出窗口在各位置时的Max value和Min value。

【输入格式】

第一行N,K,第二行为长度为N的数组

【输出格式】

第一行每个位置的Min value,第二行每个位置的Max value

【输入样例1】

8 3

1 3 -1 -3 5 3 6 7

【输出样例1】

-1 -3 -3 -3 3 3

3 3 5 5 6 7

数据规模

20%:N≤500;50%:N≤100000;100%:N≤1000000;

【题目链接】:http://noi.qz5z.com/viewtask.asp?id=t019

【题解】

最小值维护一个单调递增队列就能搞定;(a[i]<=a[i+1]
每次加入队列中的元素先和队尾比较一下,对于队尾比它大的数,直接删掉就好,因为要求的是最小值,而你加入的这个数是在框框里面的,那么如果你比这个数还大,那么你肯定没有存在的价值了;
然后对于队头元素,如果它不在框框里面也全都删掉,直到队头元素在框框里为止,然后输出队头元素;
最大值类似.
(可以在2s内出)

【完整代码】

#include <cstdio>
#include <algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

const int MAXN = 1e6+100;

int n,k,a[MAXN];
int m[MAXN],mm[MAXN],h,t;

int main()
{
    //freopen("F:\\rush.txt","r",stdin);
    scanf("%d%d",&n,&k);
    for (int i = 1;i <= n;i++)
        scanf("%d",&a[i]);
    h = 1,t = 0;
    for (int i = 1;i <= k-1;i++)
    {
        while (t>=h && m[t]>=a[i]) t--;
        t++;
        m[t] = a[i];mm[t] = i;
    }
    for (int i = k;i<= n;i++)
    {
        while (t>=h && m[t]>=a[i]) t--;
        t++;
        m[t] = a[i];mm[t] = i;
        while (mm[h]<i-k+1 && h <= t) h++;
        printf("%d",m[h]);
        if (i==n)
            puts("");
        else
            putchar(' ');
    }
    h = 1,t = 0;
    for (int i = 1;i <= k-1;i++)
    {
        while (t>=h && m[t]<=a[i]) t--;
        t++;
        m[t] = a[i];mm[t] = i;
    }
    for (int i = k;i <= n;i++)
    {
        while (t>=h && m[t]<=a[i]) t--;
        t++;
        m[t] = a[i];mm[t] = i;
        while (mm[h]<i-k+1 && h <= t) h++;
        printf("%d",m[h]);
        if (i==n)
            puts("");
        else
            putchar(' ');
    }
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(84)  评论(0编辑  收藏  举报