(poj 2823 Sliding Window)<单调队列裸题>

来源:互联网 发布:北京南站离北京站源码 编辑:程序博客网 时间:2024/05/21 15:47

传送门


Solution

  • 单调队列就是一个答案的集合,维护一个单调队列就是将有可能成为答案的数加入队列,将不可能成为答案的数移出或不加入队列。这样的好处是可以O(1)的从队头取出答案,否则需要在“窗口”的范围内枚举答案,妥妥超时
  • 假设我们将数放在数组a中,设其中有两个数满足:i<j && a[i]<a[j]就是无用的,即如果一个数比另一个数小,而且它的位置更靠前,那它一点前途也没有,既不可能成为当前窗口的最大值,窗口移动后的竞争力也很差,因此直接将它移出队列。
  • 经过这样维护的队列,一定是单调递减的,队头即为最大值
  • 计算最小值:将原数列每个数乘-1,做一遍最大值

Code

// by spli#include<cstdio>#include<algorithm>#include<iostream>#include<cstring>using namespace std;const int N=2000010;int n,k;int a[N],q[N],L,R;void work(int *a,int t){    L=1;R=0;//    for(int i=1;i<=n;++i){        while(L<=R&&a[i]>=a[q[R]]) R--;        q[++R]=i;        if(q[R]-k+1>q[L]) L++;        if(i>=k) printf("%d ",a[q[L]]*t);    }    cout<<endl;    return;}int main(){    scanf("%d%d",&n,&k);    for(int i=1;i<=n;++i) scanf("%d",&a[i]);    if(k==1){//特判k==1的情况,可能不需要        for(int i=1;i<=n;++i) printf("%d ",a[i]);        cout<<endl;        for(int i=1;i<=n;++i) printf("%d ",a[i]);        return 0;    }    for(int i=1;i<=n;++i) a[i]=-a[i];    work(a,-1);    for(int i=1;i<=n;++i) a[i]=-a[i];    work(a,1);    return 0;}