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

POJ 2823 Sliding Window (單調佇列)

題目連結

Description

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the knumbers 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

PS:單調佇列的入門題,首先我們宣告兩個陣列(ma_que[maxn],mi_que[maxn])儲存當前區間的最小值的下標,和最大值的下標,然後宣告四個變數,表示兩個陣列的頭指標位置和尾指標位置(不知道為什麼G++超時,C++就過了)。

首先要理解一下,兩個陣列的頭結點儲存的是當前區間最小(最大)值的下標,看下面這個程式碼,每次從隊尾開始查詢,一直找到當前能夠替換的資料,要是都比當前數大(小)就會一直跳到頭結點位置,然後當前最優解就會替換掉頭結點儲存的節點值。要是一個比當前數大(小)的數都沒有,當前數的座標直接插入到尾指標位置,要是有一些比當前數大(小)的數,就會替換頭指標後尾指標中間的位置。(替換是替換掉比當前更優的值)。

            while(mahead<=matail&&num[ma_que[matail]]<=num[i])//刪除隊尾元素
                matail--;
            ma_que[++matail]=i;
            while(mihead<=mitail&&num[mi_que[mitail]]>=num[i])
                mitail--;
            mi_que[++mitail]=i;

 因為每次都要保證是在當前k長度的區間中找到最小值,最大值,所以我們要保證頭指標儲存的位置一定在當前的區間中。

            while(mahead<=matail&&ma_que[mahead]<=i-k)//刪除下標超出範圍的元素
                mahead++;
            while(mihead<=mitail&&mi_que[mihead]<=i-k)
                mihead++;

結合下來;

#include <iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<stack>
#include<string>
const int maxn=1e6+10;
const int mod=100000000;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
#define lowbit(x) x&(-x)
typedef long long ll;
using namespace std;
int n,k;
int ma_ans[maxn],mi_ans[maxn];
int num[maxn],ma_que[maxn],mi_que[maxn];
int main()
{
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        int mahead=1,mihead=1,matail=0,mitail=0;
        for(int i=1;i<=n;i++)
        { 
            scanf("%d",&num[i]);
            while(mahead<=matail&&ma_que[mahead]<=i-k)//刪除下標超出範圍的元素
                mahead++;
            while(mihead<=mitail&&mi_que[mihead]<=i-k)
                mihead++;
            while(mahead<=matail&&num[ma_que[matail]]<=num[i])//刪除隊尾元素
                matail--;
            ma_que[++matail]=i;
            while(mihead<=mitail&&num[mi_que[mitail]]>=num[i])
                mitail--;
            mi_que[++mitail]=i;
            ma_ans[i]=num[ma_que[mahead]];
            mi_ans[i]=num[mi_que[mihead]];
        }
        for(int i=k;i<=n;i++)
            printf("%d ",mi_ans[i]);
        printf("\n");
        for(int i=k;i<=n;i++)
            printf("%d ",ma_ans[i]);
        printf("\n");
    }
    return 0;
}