首页 > 代码库 > 单调队列入门

单调队列入门

给定长度为n的数列a[]和整数k,求b[i] = min{a[i], ... , a[i + k - 1]}, 复杂度为O(n)

 

最开始单调队列为空,保证队列中的元素始终保持单调性

为了计算b[0],把0到k-1依次加入队列。在加入i时,当单调队列的末尾的值j满足a[j] >= a[i],则不断取出。直到双端队列为空或者a[j] < a[i]之后再于末尾加入i。

等到k-1加入队列,查看头部的值j,b[0] = a[j]。如果j = 0, 由于在之后的计算的中都不会用到了,因此从双端队列的头部删去。

 

接下里,为了计算b[i],需要在双端队列的末尾加入k。不断加入元素,就可以算出后面的b[i]的值。

 

技术分享
 1 int n, k;
 2 int a[maxn];
 3 
 4 int b[maxn];
 5 int deq[maxn];
 6 
 7 void solve() {
 8     int s = 0, t = 0;
 9     for (int i = 0; i < n; i++) {
10         //在双端队列的末尾加入i
11         while (s < t && a[deq[t - 1]] >= a[i]) t--;
12         deq[t++] = i;
13         if (i - k + 1 >= 0) {
14             b[i - k + 1] = a[deq[s]];
15             //从头部删除
16             if (deq[s] == i - k + 1) {
17                 s++;
18             }
19         }
20     }
21     for (int i = 0; i <= n - k; i++) {
22         printf("%d%d", b[i], i == n - k ? \n :  );
23     }
24 }
View Code

 

POJ2823http://poj.org/problem?id=2823

用两个双端队列维护

 

技术分享
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <queue>
 6 #include <vector>
 7 #define INF 0x3f3f3f3f
 8 #define mod 1000000007
 9 typedef long long LL;
10 using namespace std;
11 
12 const int maxn = 1e6 + 10;
13 
14 int N, len;
15 
16 int a[maxn];
17 
18 int b[maxn];
19 int deq[maxn];
20 
21 void GetMin() {
22     int s = 0, t = 0;
23     for (int i = 0; i < N; i++) {
24         while (s < t && a[deq[t - 1]] >= a[i]) t--;
25         deq[t++] = i;
26         if (i - len + 1 >= 0) {
27             b[i - len + 1] = a[deq[s]];
28             if (deq[s] == i - len + 1) {
29                 s++;
30             }
31         }
32     }
33     
34     for (int i = 0; i <= N - len; i++) {
35         printf("%d%c", b[i], i == N - len ? \n :  );
36     }
37 }
38 
39 void GetMax() {
40     int s = 0, t = 0;
41     for (int i = 0; i < N; i++) {
42         while (s < t && a[deq[t - 1]] <= a[i]) t--;
43         deq[t++] = i;
44         if (i - len + 1 >= 0) {
45             b[i - len + 1] = a[deq[s]];
46             if (deq[s] == i - len + 1) {
47                 s++;
48             }
49         }
50     }
51     
52     for (int i = 0; i <= N - len; i++) {
53         printf("%d%c", b[i], i == N - len ? \n :  );
54     }
55 }
56 
57 int main() {
58     scanf("%d%d", &N, &len);
59     for (int i = 0; i < N; i++) {
60         scanf("%d", a + i);
61     }
62     GetMin();
63     GetMax();
64     return 0;
65 }
View Code

 

单调队列入门