单调队列

 队列,从一头进入,从另一头删除的数据结构。

第一步:初始化
|_|
|_|
|_|
|_|
|_|
|_| t=h=0

第二步:从队尾加入一个元素8

|_|
|_|
|_|
|_|
|8| t=1
|_| h=0

第三步:从队尾删除一个元素

|_|
|_|
|_|
|_|
|8|
|_| t=h=0

在这里虽然8仍然存在,但是由于t=0,所以下次如果在加入一个元素会将其覆盖掉,所以我们认为t--,就是对数据的删除

 

队列的典型的题目是:poj 2823 http://poj.org/problem?id=2823

代码如下:

View Code
#include <stdio.h>

 #include <string.h>

 #include <iostream>

 using namespace std;

 

 #define N 1000010

 

 struct node{

     int m, d;

 }Inc[N], Dec[N];

 

 int mi[N], mx[N], k;

 

 bool cmpMAX(const int &a, const int &b){ return a>b; }

 bool cmpMIN(const int &a, const int &b){ return a<b; }

 

 void chk(int i, int &head, int &tail, node c[], bool cmp(const int &a, const int &b), int num)

 {                        //添加新节点到队尾,并删掉过期的头节点

     while(tail >= head && cmp(c[tail].m, num)) tail--;

     c[++tail].m = num;

     c[tail].d = i;

     while(cmpMAX(i-c[head].d+1, k)) head++;//更新了一下head,如果保存的不在可视框内,则不应该考虑,否则wa

 }

 void solve()

 {

     int n, i, j, id=0, num;

     int head_I=0, tail_I=0, head_D=0, tail_D=0;

 

     scanf("%d%d", &n, &k);

     if(n>0 && k>=1)        //初始化化队列里的第一个点

     {

         scanf("%d", &num);

         Inc[0].m = Dec[0].m = num;

         Inc[0].d = Dec[0].d = 0;

     }

     for(i=1; i<k; i++)    //初始化视窗中的点: 加入队列

     {

         scanf("%d", &num);

         chk(i, head_I, tail_I, Inc, cmpMIN, num);

         chk(i, head_D, tail_D, Dec, cmpMAX, num);

     }

     mi[id] = Inc[head_I].m;

     mx[id++] = Dec[head_D].m;

     for(; i<n; i++)        //添加并更新

     {

         scanf("%d", &num);

         chk(i, head_I, tail_I, Inc, cmpMIN, num);

         chk(i, head_D, tail_D, Dec, cmpMAX, num);

         mi[id] = Inc[head_I].m;

         mx[id++] = Dec[head_D].m;

     }

     printf("%d", mx[0]);

     for(i=1; i<id; i++) printf(" %d", mx[i]);

     printf("\n%d", mi[0]);

     for(i=1; i<id; i++) printf(" %d", mi[i]);

     printf("\n");

 }

 

 int main()

 {

     solve();

     return 0;

 }

 

 

 

你可能感兴趣的:(队列)