1. 程式人生 > >基本單調隊列

基本單調隊列

namespace ont 哪裏 特性 ace tdi 例題 span 同時

何為單調隊列?

單調隊列是一個隊列(廢話)

而且必須同時滿足下標單調和值單調兩個單調特性。

跟優先隊列不同,優先隊列直接使用堆(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 }

基本單調隊列