单调队列问题

来源:互联网 发布:将js文件引入html代码 编辑:程序博客网 时间:2024/06/18 09:53

Sliding Window

题目传送:POJ - 2823 - Sliding Window

闲来没事学学单调队列的写法,嗯,一个很奇怪的队列形式。。

单调队列是指:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

因为这里是滑动窗口,每次移动需要进行更新,所以可以用单调队列来实现。

本题用单调递增队列来求每一个区间的最小值,用单调递减队列来求每一个区间的最大值,用一个pos数组记录单调队列里每一个数出现的位置来比较是否要更新(即删去)

具体实现还是看代码吧。

AC代码:

#include <map>#include <set>#include <list>#include <cmath>#include <deque>#include <queue>#include <stack>#include <bitset>#include <cctype>#include <cstdio>#include <string>#include <vector>#include <complex>#include <cstdlib>#include <cstring>#include <fstream>#include <sstream>#include <utility>#include <iostream>#include <algorithm>#include <functional>#define LL long long#define INF 0x7fffffffusing namespace std;const int maxn = 1000005;int a[maxn];int Min[maxn];//记录每个窗口最小答案int Max[maxn];//记录每个窗口最大答案int que[maxn];//数组模拟单调队列int pos[maxn];//记录位置,用来更新int n, k;void get_min() {//维护单调递增队列,队头为最小    int head = 0, rear = 0;    for(int i = 1; i < k; i ++) {//先将前k-1个放入队列        while(rear > head && que[rear - 1] > a[i]) rear --;        que[rear] = a[i];        pos[rear] = i;        rear ++;    }    for(int i = k; i <= n; i ++) {        while(rear > head && que[rear - 1] > a[i]) rear --;        que[rear] = a[i];        pos[rear] = i;        rear ++;        while(pos[head] < i - k + 1) head ++;//因为是滑窗,所以要及时更新        Min[i] = que[head];    }}void get_max() {//维护单调递减队列,队头为最大    int head = 0, rear = 0;    for(int i = 1; i < k; i ++) {//先将前k-1个放入队列        while(rear > head && que[rear - 1] < a[i]) rear --;        que[rear] = a[i];        pos[rear] = i;        rear ++;    }    for(int i = k; i <= n; i ++) {        while(rear > head && que[rear - 1] < a[i]) rear --;        que[rear] = a[i];        pos[rear] = i;        rear ++;        while(pos[head] < i - k + 1) head ++;//因为是滑窗,所以要及时更新        Max[i] = que[head];    }}int main() {    while(scanf("%d %d", &n, &k) != EOF) {        for(int i = 1; i <= n; i ++) {            scanf("%d", &a[i]);        }        get_min();        get_max();        for(int i = k; i < n; i ++) {            printf("%d ", Min[i]);        }        printf("%d\n", Min[n]);        for(int i = k; i < n; i ++) {            printf("%d ", Max[i]);        }        printf("%d\n", Max[n]);    }    return 0;}



Subsequence

题目传送:HDU - 3530 - Subsequence

AC代码:

#include <map>#include <set>#include <list>#include <cmath>#include <deque>#include <queue>#include <stack>#include <bitset>#include <cctype>#include <cstdio>#include <string>#include <vector>#include <complex>#include <cstdlib>#include <cstring>#include <fstream>#include <sstream>#include <utility>#include <iostream>#include <algorithm>#include <functional>#define LL long long#define INF 0x7fffffffusing namespace std;const int maxn = 100005;int n, m, k;int a[maxn];int q1[maxn], q2[maxn];//单调队列记录最大和最小的位置int head1, rear1;int head2, rear2;int main() {    while(scanf("%d %d %d", &n, &m, &k) != EOF) {        head1 = rear1 = 0;        head2 = rear2 = 0;        int pre = 1;//记录可行区间的最左,i可以动态表示可行区间的最右        int ans = 0;        for(int i = 1;  i <= n; i ++) {            scanf("%d", &a[i]);            while(rear1 > head1 && a[q1[rear1 - 1]] < a[i]) rear1 --;            while(rear2 > head2 && a[q2[rear2 - 1]] > a[i]) rear2 --;            q1[rear1 ++] = i;            q2[rear2 ++] = i;            while(rear1 > head1 && rear2 > head2 && a[q1[head1]] - a[q2[head2]] > k) {//更新可行区间的最左                if(q1[head1] > q2[head2]) pre = q2[head2 ++] + 1;                else pre = q1[head1 ++] + 1;            }            if(rear1 > head1 && rear2 > head2 && a[q1[head1]] - a[q2[head2]] >= m) {//此区间的最大最小满足在m,k之间,所以更新答案                ans = max(ans, i - pre + 1);//更新答案            }        }        printf("%d\n", ans);    }    return 0;}



0 0
原创粉丝点击