基本单调队列

Posted んцγυfёìfのι

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基本单调队列相关的知识,希望对你有一定的参考价值。

何为单调队列?

单调队列是一个队列(废话)

而且必须同时满足下标单调和值单调两个单调特性。

跟优先队列不同,优先队列直接使用堆(heap)来实现,如何删去特定下标元素?不明。

本人喜欢用单调队列存下标,这样比存值不知道高到哪里去了。

新来一个元素,进队。之后特判长度有没有超过。超过则把最前面的元素出队。

之后,如果不满足性质,就把前面的元素顶掉,直到满足性质为止。

然后才可以把队首元素拿来用。

有几个很坑的地方,具体看代码注释。

(为什么top是队尾而tail是队首?laughcry)

例题:洛谷P1886,高级模板题。

AC代码:

 

 1 #include <cstdio>
 2 using namespace std;
 3 const int N=1000005;
 4 
 5 int n,k,a[N];
 6 int p1[N],p2[N],top1,top2,tail1=1,tail2=1;///存下标
 7 int ans2[N];///本题特殊需要
 8 ///p1 small p2 large
 9 int main()
10 {
11     scanf ("%d%d",&n,&k);
12     for(int i=1;i<k;i++)///读入时顺便处理了。因为本题特殊性,先读到k
13     {
14         scanf ("%d",&a[i]);
15         p1[++top1]=p2[++top2]=i;
16         while(a[p1[top1]]<=a[p1[top1-1]] && top1>tail1)
17         {
18             p1[top1-1]=p1[top1];
19             top1--;
20         }
21         while(a[p2[top2]]>=a[p2[top2-1]] && top2>tail2)
22         {
23             p2[top2-1]=p2[top2];
24             top2--;
25         }
26     }
27     for(int i=k;i<=n;i++)///继续开始读入
28     {
29         scanf ("%d",&a[i]);
30         p1[++top1]=p2[++top2]=i;///存下标!不要存a[i],直接存i
31         if(p1[top1]-p1[tail1]+1>k) tail1++;///注意顺序:
32         if(p2[top2]-p2[tail2]+1>k) tail2++;///①进队 ②出队
33         while(a[p1[top1]]<=a[p1[top1-1]] && top1>tail1)///③前进
34         {
35             p1[top1-1]=p1[top1];///这里注意:top>tail时才能出队
36             top1--;///还要注意:while里面的那个,一定要套上a[],因为是存下标
37         }          ///同理,出队时的if里也要套上p[],因为是下标长度限制
38         while(a[p2[top2]]>=a[p2[top2-1]] && top2>tail2)
39         {
40             p2[top2-1]=p2[top2];
41             top2--;
42         }
43         printf("%d ",a[p1[tail1]]);///④才可以拿来用
44         ans2[i]=a[p2[tail2]];      ///用的时候也要注意:存的下标,要套上a[]
45     }
46     printf("\n");
47     for(int i=k;i<=n;i++) printf("%d ",ans2[i]);
48     return 0;
49 }

 

以上是关于基本单调队列的主要内容,如果未能解决你的问题,请参考以下文章

[数据结构读书笔记 ] 队列 以及 单调队列

[数据结构读书笔记 ] 队列 以及 单调队列

[数据结构读书笔记 ] 队列 以及 单调队列

单调队列的基本运用模版

心得单调队列

单调队列&单调栈归纳