1. 程式人生 > >單調佇列 POJ 2823 Sliding Window

單調佇列 POJ 2823 Sliding Window

 

Sliding Window

An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich is moving from the very left of the array to the very right. You can only see the k 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 position Minimum value Maximum 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

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 integers n and k which are the lengths of the array and the sliding window. There are n 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

題意:求區間寬為M,從左到右平移,求每個區間的最大值,最小值。

解法單調佇列:

單調佇列顧名思義維護一個單調減或單調增的佇列,為了得到這個區間的最大值最小值,我們只需要和隊頭去比較就行了。

要的得到最小值,就要維護單調增的,因為這樣隊頭才最小。

然後這個題還要注意,每個元素必須要在 那一時刻的區間類,佇列的每個元素的小下標必須維護大於區間前端。

接下來陣列模擬就行啦……

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e6+7;
int n,m;
struct node
{
    int id;
    int val;
}q[maxn];
int ansmin[maxn];
int ansmax[maxn];
int a[maxn];
int head,tail;
void getmin()
{
    ///構造一個單調增的佇列保證隊頭的元素始終是最小的,每次只比較隊頭
    ///先將前k-1個入隊
    int i;
    head=1;
    tail=0;
    for(i=1;i<m;++i)
    {
        while(head<=tail&&q[tail].val>=a[i])/// 隊尾元素大於將要入隊的元素
            --tail;
        q[++tail].val=a[i];
        q[tail].id=i;
    }
    for(;i<=n;++i)
    {
        while(head<=tail&&q[tail].val>=a[i])/// 隊尾元素大於將要入隊的元素
            --tail;
        q[++tail].val=a[i];
        q[tail].id=i;
        while(q[head].id<i-m+1)
        {
            ++head;
        }
        ansmin[i-m+1]=q[head].val;
    }
    for(int i=1;i<n-m+1;++i)
        cout<<ansmin[i]<<' ';
    cout<<ansmin[n-m+1]<<endl;
}
void getmax()
{
    int i;
    head=1;
    tail=0;
    ///構造單調減的佇列
    for(i=1;i<m;++i)
    {
        while(head<=tail&&q[tail].val<=a[i])
            tail--;
        q[++tail].id=i;
        q[tail].val=a[i];
    }
    for(;i<=n;++i)
    {
        while(head<=tail&&q[tail].val<=a[i])
            tail--;
        q[++tail].id=i;
        q[tail].val=a[i];
        while(q[head].id<i-m+1)
            ++head;
        ansmax[i-m+1]=q[head].val;

    }
    for(int i=1;i<n-m+1;++i)
        cout<<ansmax[i]<<' ';
    cout<<ansmax[n-m+1]<<endl;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;++i)
            scanf("%d",&a[i]);
        getmin();
        getmax();


    }
    return 0;
}