本题地址:http://www.luogu.org/problem/show?pid=1440
题目描述
一个含有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
【思路】
单调队列。
题目比较裸,直接用一个单调队列维护即可。单调队列第一次写,总结有如下需要注意的地方:
1、
注意维护的是什么,本题中维护的是一个满足序号 >=i-m+1 的序列,其中序列满足a值单调递增。
2、
注意边界,特别是初始情况下是否满足平凡情况。
3、
注意单调队列的维护添加
与取值之间的顺序,取决于使用单调队列的目的。
还有需要注意的是题目中要求i之前m个,每次取值是算上当前a的所以需要错开一个。
【代码】
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 const int maxn = 2000000+10; 6 7 int a[maxn],que[maxn],d[maxn]; 8 int n,m,front,rear; 9 10 inline int read_int() { 11 char c; c=getchar(); 12 while(!isdigit(c)) c=getchar(); 13 14 int x=0; 15 while(isdigit(c)) { 16 x=x*10+c-‘0‘; 17 c=getchar(); 18 } 19 return x; 20 } 21 22 int main() { 23 n=read_int(); m=read_int(); 24 a[0]=1<<30; //边界不取 25 front=rear=1; 26 for(int i=1;i<=n;i++) 27 { 28 a[i]=read_int(); 29 30 //注意顺序 31 while(front<=rear && (que[front]<(i-m+1))) front++; 32 33 while(front<=rear && a[i]<=a[que[rear]]) rear--; //注意维护a值最小的 34 35 que[++rear]=i; 36 37 d[i]=a[que[front]]; 38 39 } 40 cout<<0<<"\n"; 41 for(int i=1;i<n;i++) cout<<d[i]<<"\n"; 42 return 0; 43 }
时间: 2024-10-10 20:23:52