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; }