您的位置:首页 > 其它

poj2823 单调队列,双端队列

2018-03-04 19:33 330 查看
其实可以用线段树来做..

这道题的具体做法就是维护一个数组
队头s和队尾t。
我们需要维护两个东西,第一个是单调性,第二个是长度。
我们每次加入一个新值,我们是放到尾部。
这个时候我们维护单调性,从尾部开始把大于当前值的全部删除,反正我们找的是最小值,所以不影响。

之后处理完单调性后我们把新值插入。
插入新值后我们形成了新的滑动区间,记录一下最小元素,也就是队伍头部的元素。
之后我们要处理长度问题。看看当前队伍头部的那个值的位置是否已经出去了,就是已经超出滑动区间了,如果
超出了,我们s++即可。如果没有我们就不用管。

重复这个过程即可
//http://blog.csdn.net/waduan2/article/details/52416523代码

#include<cstring>  
#include<cstdio>  
#define N 1000050  
#define INF 2147483647  
using namespace std;  
int n,k;  
int a
;  
struct Elem{  
    int k,num;  
}Queue
;  
int l=1,r=1;  
inline void GetMin(){  
    memset(Queue,0,sizeof Queue);  
    Queue[0].k=-INF;  
    l=1,r=1;  
    for(int i=1;i<=k;i++){  
        while(Queue[r].k>=a[i] && r>=l) r--;  
        Queue[++r].k=a[i];  
        Queue[r].num=i;  
    }  
    for(int i=k;i<=n;i++){  
        while(Queue[r].k>=a[i] && r>=l) r--; //维护单调性   
        Queue[++r].k=a[i];  
        Queue[r].num=i;  
        while(Queue[l].num<=i-k) l++;  //维护队列下标范围k以内   
        printf("%d ",Queue[l].k);  
    }   
}  
inline void GetMax(){  
    memset(Queue,0,sizeof Queue);  
    Queue[0].k=INF;  
    l=1,r=1;  
    for(int i=1;i<=k;i++){  
        while(Queue[r].k<=a[i] && r>=l) r--;  
        Queue[++r].k=a[i];  
        Queue[r].num=i;  
    }  
    for(int i=k;i<=n;i++){  
        while(Queue[r].k<=a[i] && r>=l) r--;  
        Queue[++r].k=a[i];  
        Queue[r].num=i;  
        while(Queue[l].num<=i-k) l++;  
        printf("%d ",Queue[l].k);  
    }   
}  
int main(){  
    scanf("%d%d",&n,&k);  
    for(int i=1;i<=n;i++)  
        scanf("%d",a+i);  
    GetMin();  
    printf("\n");  
    GetMax();  
return 0;  
}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: