洛谷 P1440 求m区间内的最小值(单调队列 滑窗模板)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kzn2683331518/article/details/81301257

题目描述:https://www.luogu.org/problemnew/show/P1440

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

输入样例#1: 复制

6 2
7 8 1 4 3 2

输出样例#1: 复制

0
7
7
1
1
3 

题目分析:

从前m个数开始,遍历一个下标范围不超过m的单调递增队列,这个队列的第一个元素就是这个区间的最小值,其次分别是第二小,第三小。。。。

每次区间后移加入新元素,如果加入该元素不能继续维持队列的单调递增,那么要把当前队尾删去,直到该元素可以加入为止。

然后检查队首元素是否在该区间内,如果不在就要出队。

代码:

//#include <bits/stdc++.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define ll long long
#define INF 0x3f3f3f3f
inline int read(){//读入整数
    int k = 0, f = 1; char c = getchar();
    while (c<'0' || c>'9')c == '-' && (f = -1), c = getchar();
    while ('0' <= c&&c <= '9')k = k * 10 + c - '0', c = getchar();
    return k*f;
}
int a[2000006], n;

//递增单调队列模板,维护区间长度不超过m的最小值
pair<int,int> que[2000006];//first:值  second:下标
int l,r,m;//头指针,尾指针,维护区间长度,入队数 = r-l+1;

//清空队列
inline void qclear(){l=1,r=0;}

//加入新元素,有效区间长度为m
void qpush(int x, int idx){
    while(r>=l && x<=que[r].first)r--;//如需维护最大值,将此处<=改为>=即可
    que[++r]=make_pair(x,idx);
    while(que[l].second<=idx-m)l++;
}

//返回当前区间最大值
inline int qmax(){return que[l].first; }

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    qclear();
    puts("0");

    for(int i=1;i<n;i++){
        qpush(a[i], i);
        printf("%d\n",qmax());
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/kzn2683331518/article/details/81301257
今日推荐