POJ 2823 Sliding Window(单调队列)

来源:互联网 发布:绝对领域 知乎 编辑:程序博客网 时间:2024/04/24 14:44

题意:给定一个长度为n的序列,依次求出(i,i+k-1) (i∈(0,n-1),i<=n-k)中最小的数和最大的数。


本题有多种解法。首先,暴力的时间复杂度是O((n-k)*klogk),所以pass。

解法1:维护一个单调递增的队列(手写),队头即为最小值。同理求出最大值。

解法2:维护一个优先队列(priority_queue即可)

解法3:线段树


这里给出单调队列解法:

#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<queue>#include<set>#include<map>#include<vector>#include<cmath>#define ll __int64#define INF 0x3fffffff#define M 1000005using namespace std;int n,k;int a[M];int Q[M];//单调队列int t[M];//记录队列中元素的下标void calcMin(){    int head=1,tail=0;    //初始化队列    for(int i=0;i<k-1;i++){        while(a[i]<=Q[tail]&&tail>=head){            tail--;        }        Q[++tail]=a[i];        t[tail]=i;    }    for(int i=k-1;i<n;i++){        while(a[i]<=Q[tail]&&tail>=head){            tail--;        }        Q[++tail]=a[i];        t[tail]=i;        while(t[head]<i-k+1) head++;        cout<<Q[head]<<" ";    }    cout<<endl;}void calcMax(){    int head=1,tail=0;    for(int i=0;i<k-1;i++){        while(a[i]>=Q[tail]&&tail>=head){            tail--;        }        Q[++tail]=a[i];        t[tail]=i;    }    for(int i=k-1;i<n;i++){        while(a[i]>=Q[tail]&&tail>=head){            tail--;        }        Q[++tail]=a[i];        t[tail]=i;        while(t[head]<i-k+1) head++;        cout<<Q[head]<<" ";    }    cout<<endl;}int main(){    //freopen("d:\\Test.txt","r",stdin);    cin>>n>>k;    for(int i=0;i<n;i++){        scanf("%d",&a[i]);    }    memset(Q,0,sizeof(Q));    calcMin();    calcMax();    return 0;}


0 0