【洛谷P1886】滑动窗口

这个题数据范围10^6,nlogn很悬,所以我们考虑用单调队列

单调队列的性质,保证队列单调递减/递增,因此我们可以通过维护单调队列,来方便的查询区间最大值、最小值

#include<iostream>
#include<cstdio>
using namespace std;
struct in
{
    int zhi,wei;
}ter[1000010];
int shu[1000010],mi[1000010],mx[1000010],n,k,head,tail;
inline void cl(int x)
{
    while(ter[head].wei<x-k+1&&head<=tail)//凡是在窗口外的一律弹出 
        head++;
}
inline void pu1(int x)
{
    while(shu[x]<ter[tail].zhi&&head<=tail)//保证队列单调递增,凡是比这个数大的就都没有可能成为答案了,因为他们入队在前,值还大,而凡是可以与他们在一个队列里的就意味着有窗口能将他们一起覆盖 
        tail--;
    ter[++tail]=(in){shu[x],x};
    mi[x]=ter[head].zhi;
}
inline void pu2(int x)
{
    while(shu[x]>ter[tail].zhi&&head<=tail)//同理保持单调递减 
        tail--;
    ter[++tail]=(in){shu[x],x};
    mx[x]=ter[head].zhi;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&shu[i]);
    head=tail=1,mi[1]=shu[1],ter[1]=(in){shu[1],1};
    for(int i=2;i<=n;i++)
        cl(i),pu1(i);
    head=tail=1,mx[1]=shu[1],ter[1]=(in){shu[1],1};
    for(int i=2;i<=n;i++)
        cl(i),pu2(i);
    for(int i=k;i<=n;i++)
        printf("%d ",mi[i]);
    printf("\n");
    for(int i=k;i<=n;i++)
        printf("%d ",mx[i]);
    printf("\n");
}

 

posted @ 2017-10-27 11:21  那一抹落日的橙  阅读(228)  评论(0编辑  收藏  举报