何为单调队列?
单调队列是一个队列(废话)
而且必须同时满足下标单调和值单调两个单调特性。
跟优先队列不同,优先队列直接使用堆(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 }