Live2D
博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

P1440 求m区间内的最小值

题目描述

一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。

输入输出格式

输入格式:

第一行两个数n,m。

第二行,n个正整数,为所给定的数列。

输出格式:

n行,第i行的一个数ai,为所求序列中第i个数前m个数的最小值。

输入输出样例

输入样例1:

6 2
7 8 1 4 3 2

输出样例1:

0
7
7
1
1
3 

说明

【数据规模】

m≤n≤2000000

ai<=3*107

思路:

  单调队列,首先我们要明确一件事情,就是对于i与j来说,如果i<=j,那么a[j]对单调队列的贡献一定比a[i]的贡献大,也就是说,如果当a[i]与a[j]同时存在时,我们一定会选择a[j]。那么我们就可以保证在当前队列中的元素一定是最优的,之后我们再维护一下每一项的时间即可。

代码:

 

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<cmath>

using namespace std;

static int n,m;

struct Mt{
    int dis;
    int pos;
};

Mt mt[2000008];

deque < Mt > q;

long long read()
{
    long long x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
    {
        mt[i].dis=read();
        mt[i].pos=i;
    }
    printf("0\n");
    for(int i=1;i<n;++i)
    {
        while(!q.empty()&&q.back().dis>=mt[i].dis) q.pop_back();//维护单调性 
        q.push_back(mt[i]);//加入元素 
        while(q.front().pos<=i-m) q.pop_front();//删除在区间外的元素 
        printf("%d\n",q.front().dis);//输出,操作保证了队列的最优性 
    }
    return 0;
}

 

posted @ 2019-06-29 14:39  _hhs  阅读(239)  评论(0编辑  收藏  举报