POJ2823(单调队列初步)

来源:互联网 发布:以色列 科技 知乎 编辑:程序博客网 时间:2024/06/05 16:21

POJ2823(单调队列初步)

滚动窗口问题,单调队列的入门题

假设我要求最大值

  • 思路是创建一个队列,每读入一个数据就和队尾的元素比较如果他大于对尾的元素,队尾就被删除,队尾再往前一个,直到这个数据比队尾小
  • 因为是窗口滚动,如果窗口已经离开队首元素,则删除队首元素,对手元素的下一个为队首
  • 因为此时要用到下标,所以队列里的值应该是元素的下标

对于这种有指针的题,代码细节非常重要,也是我最讨厌的

  1. 在开始循环之前,把1~k-1的元素都放进去
  2. 先循环删队尾,删完后再把要放的元素放进去
  3. 队列删空后立刻停止
  4. l,r都是直接指向队列的首位元素的
  5. 当i-k >= q[l]时,需要删除队首元素
  6. 应该先把要放的元素放进去,再考虑删除队首元素的问题

下面是代码

//单调队列#include<cstdio>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;const int MAXN = 1e+6 + 10;int l = 1, r = 0;   //单调队列的左右指针int p[MAXN], q[MAXN]; int n, k;int main(){    cin >> n >> k;     for(int i = 1; i <= n; i++)        cin >> p[i];    q[++r] = 1;     if(k == 1) cout << p[q[l]] << " ";    for(int i = 2; i <= n; i++)    {        while(p[i] < p[q[r]])        {            r--;            if(r < l) break;        }        q[++r] = i;        if((i-k) >= q[l]) l++;        if(i >= k) cout << p[q[l]] << " ";    }    cout << endl;    memset(q, 0, sizeof(q));    r = 0, l = 1;    q[++r] = 1;    if(k == 1) cout << p[q[l]] << " ";    for(int i = 2; i <= n; i++)    {        while(p[i] > p[q[r]])        {            r--;            if(r < l) break;        }        q[++r] = i;        if((i-k) >= q[l]) l++;        if(i >= k) cout << p[q[l]] << " ";    }    return 0;}
0 0