区间最小最大值(单调队列)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,w,a[1000001],q[10000001],id[10000001]; 4 void min() 5 { 6 int st=0,ed=0; 7 for(int i=1;i<=w;i++) 8 { 9 while(st<ed&&q[ed]>a[i]) 10 { 11 ed--; 12 } 13 ed++; 14 q[ed]=a[i]; 15 id[ed]=i; 16 } 17 for(int i=w+1;i<=n;i++) 18 { 19 while(st<ed&&id[st+1]<i-w) 20 { 21 st++; 22 } 23 printf("%d ",q[st+1]); 24 while(st<ed&&q[ed]>a[i]) 25 { 26 ed--; 27 } 28 ed++; 29 q[ed]=a[i]; 30 id[ed]=i; 31 } 32 while(st<ed&&id[st+1]<n+1-w) 33 { 34 st++; 35 } 36 printf("%d\n",q[st+1]); 37 } 38 void max() 39 { 40 int st=0,ed=0; 41 for(int i=1;i<=w;i++) 42 { 43 while(st<ed&&q[ed]<a[i]) 44 { 45 ed--; 46 } 47 ed++; 48 q[ed]=a[i]; 49 id[ed]=i; 50 } 51 for(int i=w+1;i<=n;i++) 52 { 53 while(st<ed&&id[st+1]<i-w) 54 { 55 st++; 56 } 57 printf("%d ",q[st+1]); 58 while(st<ed&&q[ed]<a[i]) 59 { 60 ed--; 61 } 62 ed++; 63 q[ed]=a[i]; 64 id[ed]=i; 65 } 66 while(st<ed&&id[st+1]<n+1-w) 67 { 68 st++; 69 } 70 printf("%d\n",q[st+1]); 71 } 72 int main() 73 { 74 scanf("%d %d",&n,&w); 75 for(int i=1;i<=n;i++) 76 { 77 scanf("%d",&a[i]); 78 } 79 min(); 80 max(); 81 return 0; 82 }
题目:输入n个整数 给定w长的区间,求每个区间的最小最大值。
第一行输入n、w,
第二行开始输入n个整数;
输出时,第一行输出每个区间的最小值,用空格隔开;第二行输出每个区间的最大值,用空格隔开;
要求 1<n<10^6 1<w<=n
样例输入
8 3
1 3 -1 -3 5 3 6 7
样例输出
-1 -3 -3 -3 3 3
3 3 5 5 6 7
看到这个n的要求就知道 O(n^2)是肯定过不了了 必须在O(n)解决问题 于是就用了这个单调队列
大致思路如下
在队列中 我们要维护一个单调递增/递减的队列
以单调递减为例 给出样例
3 1 8 2 4 7
首先 3入队 此时队首元素为3;
接着 1入队;
1<3;
此时队首元素为3,队尾元素为1;
接着 8入队;
8>1;
为了维护递减 我们将1删除;
此时队首元素为3,队尾元素为8;
8>3;
为了维护递减 我们将3删除;
此时队首元素为8;
接着 2入队;
2<8;
此时队首元素为8,队尾元素为2;
接着4入队;
4>2;
为了维护递减 我们将2删除;
此时队首元素为8,队尾元素为4;
接着 7入队;
7>4;
为了维护递减 我们将4删除;
此时队首元素为8,队尾元素为7;
7<8;
此时 该单调队列已维护完成;
队列为 8 7;
此时 最大值就是8;
这种方法可以大大降低时间复杂度 简化排序并增强稳定性 直接得出结果 省去了其他元素排序的部分;