单调队列学习

来源:互联网 发布:孙玉伯 知乎 编辑:程序博客网 时间:2024/06/01 09:41

单调队列就是一个维护递增或者递减元素的队列。

当一个新的元素出现的时候,判断它与队尾元素的大小,不满足则出队,直到满足。再把新的元素压入队列。

经典的例题是 poj2823.

给一个序列和m,问这个序列所有长度为m的区间最大,最小值是多少。

显然,如果暴力时间复杂度为O(N*m) 不超时就怪了。

这题要在维护单调队列是保存答案,时间复杂度o(n)。

开一个结构体存模拟队列,一个元素存值,一个存位置。当队列中的元素已经不再m的范围内是要出队列。这个方法看了http://blog.csdn.net/cabi_zgx/article/details/52701266。

#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>using namespace std;struct node{    int x,y;}v[1010000]; //x表示值,y表示位置 可以理解为下标int a[1010000],n,m,mx[1010000],mn[1010000];void getmin(){    int i,head=1,tail=0;    for(i=1;i<m;i++)    {        while(head<=tail && v[tail].x>=a[i]) tail--;        v[++tail].x=a[i],v[tail].y=i;    }    for(;i<=n;i++)    {        while(head<=tail && v[tail].x>=a[i]) tail--;        v[++tail].x=a[i],v[tail].y=i;        while(v[head].y<i-m+1) head++;        mn[i-m+1]=v[head].x;    }}void getmax() //最大值同最小值的道理,只不过是维护的是递减队列{    int i,head=1,tail=0;    for(i=1;i<m;i++)    {        while(head<=tail && v[tail].x<=a[i]) tail--;        v[++tail].x=a[i],v[tail].y=i;    }    for(;i<=n;i++)    {        while(head<=tail && v[tail].x<=a[i]) tail--;        v[++tail].x=a[i],v[tail].y=i;        while(v[head].y<i-m+1) head++;        mx[i-m+1]=v[head].x;    }}int main(){    int i,j;    scanf("%d%d",&n,&m);    for(i=1;i<=n;i++)scanf("%d",&a[i]);    getmin();    getmax();    for(i=1;i<=n-m+1;i++)     if(i==1)printf("%d",mn[i]);     else printf(" %d",mn[i]);    printf("\n");    for(i=1;i<=n-m+1;i++)     if(i==1)printf("%d",mx[i]);     else printf(" %d",mx[i]);    printf("\n");    return 0;}


原创粉丝点击