1. 程式人生 > >POJ2823-Sliding Window

POJ2823-Sliding Window

IT 區間 for urn pac LG div clu can

給定兩個數n和k,接下來給出n個數的數列。每次維護一個長度為k的窗口,求出這個範圍的最大值和最小值。每次向右移動一個單位。

考慮如何得出一個區間的最大值,每次增加一個數,如果這個數比當前的最大值小,如何是可以不用維護的。如果比當前值大,那麽就要考慮。但是當這個最大值在最左邊的時候,它下一次就不能在這個區間了。所以我們要維護的是一個值可以存在的最左的位置。即位置i的生存期最多是i+k,但如果中間出現比它大的數,那麽就沒必要維護這個數了,可以用出現的數代替它。因為它總是比維護當前的數更優,無論是數值上還是位置上。

也就是說,我們要維護一個遞減的數列,可以用單調隊列實現做到O(n)的復雜度。

最小值同理,代碼如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <algorithm>
using namespace std;

int n,k,v[2333333],q[23333333];
int main() {
    while(~scanf("%d%d",&n,&k)){
        for(int i=1;i<=n;++i)
            scanf("%d",&v[i]);
        
        
int l=1,r=1; q[1]=0; v[0]=1e9; for(int i=1;i<=n+1;++i){ while(l<=r&&q[l]+k<i) ++l; if(i<=k) ; else printf("%d ",v[q[l]]); while(l<=r&&v[q[r]]>=v[i])
--r; q[++r]=i; } puts(""); //printf("%d\n",v[q[l]]); l=1,r=1; q[1]=0; v[0]=-1e9; for(int i=1;i<=n+1;++i){ while(l<=r&&q[l]+k<i) ++l; /* for(int j=l;j<=r;++j) printf("%d ",v[q[j]]); puts(""); */ if(i<=k) ; else printf("%d ",v[q[l]]); while(l<=r&&v[q[r]]<=v[i]) --r; q[++r]=i; } puts(""); //printf("%d\n",v[q[l]]); } return 0; }

POJ2823-Sliding Window