关键字
队列,合并果子,窗户,广告印刷,最长XX子序列,志愿者选拔,动态规划,烽火传递
正文
单调队列,望文生义,就是指队列中的元素是单调的。如:{a1,a2,a3,a4……an}满足a1<=a2<=a3……<=an,a序列便是单调递增序列。同理递减队列也是存在的。
单调队列的出现可以简化问题,队首元素便是最大(小)值,这样,选取最大(小)值的复杂度便为o(1),由于队列的性质,每个元素入队一次,出队一次,维护队列的复杂度均摊下来便是o(1)。
如何维护单调队列呢,以单调递增序列为例:
1、如果队列的长度一定,先判断队首元素是否在规定范围内,如果超范围则增长对首。
2、每次加入元素时和队尾比较,如果当前元素小于队尾且队列非空,则减小尾指针,队尾元素依次出队,直到满足队列的调性为止
要特别注意头指针和尾指针的应用。
/****************************** * author :crazy_石头 * data structure: 单调队列 * created time:2013/10/31 18:32 * Pro:POJ 2823 * Judge Status:Accepted * Memory:4063K * Time:6813MS * PS:其实可以优化输入输出加速的,据说可加速到500+ms,ORZ *******************************/ #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define rep(i,h,n) for(int i=(h);i<=(n);i++) const int maxn=1000000+5; int a[maxn],q1[maxn],q2[maxn];//q1、q2存储下标,元素的值可以通过访问下标间接访问到; int head1,tail1,head2,tail2,index1,index2,k,n; inline void Enqueue(int cur)//维护插入操作,单调递减队列; { while(head1<=tail1&&a[q1[tail1]]<=a[cur])//队列不空且待插元素大于队尾元素则让队尾元素出队直到待插元素小于队尾元素 tail1--;//找到位置,插入新元素; q1[++tail1]=cur;// tail1其实还没有值,tail-1才有值。 } inline void enqueue(int cur)//单调递增队列; { while(head2<=tail2&&a[q2[tail2]]>=a[cur])//开始应该是head2<tail2; tail2--; q2[++tail2]=cur; } inline void Dequeue(int cur) { while(q1[head1]<cur-k+1) head1++;//队首元素不在范围之内就删除它; printf("%d",a[q1[head1]]);//队首元素最大; } inline void dequeue(int cur) { while(q2[head2]<cur-k+1) head2++; printf("%d",a[q2[head2]]); } int main() { while(scanf("%d%d",&n,&k)!=EOF) { head1=head2=index1=index2=1; tail1=tail2=0; rep(i,1,n) scanf("%d",&a[i]); rep(i,1,k-1)//维护队列2; enqueue(i); rep(i,k,n) { enqueue(i); dequeue(i); if(i!=n) printf(" "); } printf("\n"); rep(i,1,k-1)//维护队列1,队首元素最大; Enqueue(i); rep(i,k,n) { Enqueue(i); Dequeue(i); if(i!=n) printf(" "); } printf("\n"); } return 0; } |
* This source code was highlighted by YcdoiT. ( style: Moria )