最近学到了dp,一开始以为思维的体操是时候绽放了....
傲娇.jpg
....但是....
下面回归正题:
单调队列:单调队列分为两种,即单调递增和单调递减队列,简单的理解就是基本队列赋予严格的递增或递减的单调性即可。
单调队列一般用于优化,一般有如下用途。

下面给一道单调队列的模版题:
题目链接:
题意:意思就是给出一个区间长度k和n个元素的数组a, 从a的第一个k大小的连续区间开始直到最后一个连续区间,找到每次区间里的最大值和最小值,具体输出形式见题面。
本题思路:刚好满足单调队列的性质,每次维护区间内的最值并保存就ok。
参考代码:

1 #include <iostream>
2 #include <deque>
3 #include <cstdio>
4 using namespace std;
5
6 typedef pair<int ,int > P;
7 const int maxn = 1e6 + 5;
8 int a[maxn], n, k, Max[maxn], Min[maxn], nummax = 0, nummin = 0;
9
10 void getMax() {
11 deque <P> p;
12 P now;
13 p.push_front(make_pair(a[0], 0));
14 if(k == 1) Max[nummax ++] = a[0];
15 for(int i = 1; i < n; i ++) {
16 now = p.back();
17 while(now.first < a[i]) {
18 p.pop_back();
19 if(!p.empty())
20 now = p.back();
21 else break;
22 }
23 p.push_back(make_pair(a[i], i));
24 if(i - p.front().second > k - 1) p.pop_front();
25 if(i > k - 2) Max[nummax ++] = p.front().first;
26 }
27 }
28
29 void getMin() {
30 if(k == 1) Min[nummin ++] = a[0];
31 deque <P> p;
32 P now;
33 p.push_front(make_pair(a[0], 0));
34 for(int i = 1; i < n; i ++) {
35 now = p.back();
36 while(now.first > a[i]) {
37 p.pop_back();
38 if(!p.empty()) now = p.back();
39 else break;
40 }
41 p.push_back(make_pair(a[i], i));
42 if(i - p.front().second > k - 1) p.pop_front();
43 if(i > k - 2) Min[nummin ++] = p.front().first;
44 }
45 }
46
47 int main () {
48 ios::sync_with_stdio(false);
49 cin >> n >> k;
50 for(int i = 0; i < n; i ++) cin >> a[i];
51 getMax();
52 getMin();
53 for(int i = 0; i < nummin ; i ++) {
54 if(i > 0) cout << ' ';
55 cout << Min[i];
56 }
57 cout << endl;
58 for(int i = 0; i < nummax; i ++) {
59 if(i > 0) cout << ' ';
60 cout << Max[i];
61 }
62 cout << endl;
63 return 0;
64 }
下面给出数组模拟队列版本的参考代码吧:

1 #include <iostream>
2 using namespace std;
3
4 typedef pair<int ,int > P;
5 const int maxn = 1e6 + 5;
6 int a[maxn], n, k, Max[maxn], Min[maxn], nummax = 0, nummin = 0;
7 P v[maxn];
8
9 void getMin() {
10 int i, head = 1, tail = 0;
11 for(i = 0; i < k - 1; i ++) {
12 while(head <= tail && v[tail].first >= a[i]) tail --;
13 v[++ tail].first = a[i], v[tail].second = i;
14 }
15 for(; i < n; i ++) {
16 while(head <= tail && v[tail].first >= a[i]) tail --;
17 v[++tail].first = a[i], v[tail].second = i;
18 while(i - v[head].second > k - 1) head ++;
19 Min[nummin ++] = v[head].first;
20 }
21 }
22
23 void getMax() {
24 int i, head = 1, tail = 0;
25 for(i = 0; i < k - 1; i ++) {
26 while(head <= tail && v[tail].first <= a[i]) tail --;
27 v[++ tail].first = a[i], v[tail].second = i;
28 }
29 for(; i < n; i ++) {
30 while(head <= tail && v[tail].first <= a[i]) tail --;
31 v[++ tail].first = a[i], v[tail].second = i;
32 while(i - v[head].second > k - 1) head ++;
33 Max[nummax ++] = v[head].first;
34 }
35 }
36
37 int main () {
38 ios::sync_with_stdio(false);
39 cin >> n >> k;
40 for(int i = 0; i < n; i ++) cin >> a[i];
41 getMin();
42 getMax();
43 for(int i = 0; i < nummin ; i ++) {
44 if(i > 0) cout << ' ';
45 cout << Min[i];
46 }
47 cout << endl;
48 for(int i = 0; i < nummax; i ++) {
49 if(i > 0) cout << ' ';
50 cout << Max[i];
51 }
52 cout << endl;
53 return 0;
54 }
单调栈:单调栈和单调队列的定义类似,也可以简单理解为基本的栈赋予严格的递增或递减单调性即可。
单调栈的本质为:当一个数a在另一个数b前面且比b大,那么数a就在找第一个比某数小的问题里就完全没有考虑的必要了,他被b完全屏蔽了。所以利用单调栈,可以找到从左或右第一个比某个值小或大的元素的位置。
来源:https://www.cnblogs.com/bianjunting/p/10566469.html
