1. 程式人生 > >單調佇列 (POJ2823)

單調佇列 (POJ2823)

前幾天做過這題...當時使用線段樹做的....要跑9500MS才能過...今天看了下單調佇列...以為很難...但理解一下..發現單調佇列其實很簡單..

單調佇列是從數列前掃到數列後...維護一個最值或者一個所需的最優解之類的...每次的最優解都是在佇列的頭....所以要一直維護佇列..使其從頭到尾都是單調的..要能保證如果當前頭要出去了...後面的元素能馬上頂上來作為頭...

就拿POJ2823來舉例....題目要求是給了一串n個數...從左到右每次框k個連續數..問每次框的數中最大數和最小數是什麼..樣例輸入輸出:

Sample Input

8 3
1 3 
-1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7

就拿樣例說....準備一個佇列...Myqueue...h代表隊列頭( 裡面存的是下標不是數..為了是判斷隊首出列)..p代表隊列尾..初始值h=1,p=0...就拿每次要一段最小值的佇列變化過程來描述一下:

1、插入第1個數 Myqueue = { 1 } h=1; p=1 小於所給的框..還不需輸出

2、插入第2個數 Myqueue= { 1 2 } h=1; p=2 ( 因為2號元素比1號元素大...先排到後面 ) 小於所給的框..還不需輸出

3、插入第3個數 Myqueue= { 3 } h=1; p=1; ( 因為3號元素為-1比1號元素的1和2號元素的3都要小~~所以一直擠到最前面...1,2都出列 ) 輸出 a[ Myqueue[h] ]的值 -1

4 、插入第4個數 Myqueue={ 4 } h=1; p=1; ( 因為4號元素比3號元素小....所以擠掉3號元素 ) 輸出 a[ Myqueue[h] ]的值 -3

5、插入第5個數 Myqueue={ 4 5 } h=1; p=2 ( 因為5號元素比4號元素大...先排到後面 ) 輸出 a[ Myqueue[h] ]的值 -3

6、插入第6個數 Myqueue={4 6 } h=1; p=2 ( 因為6號元素比5號元素小....但是又沒有4號元素小..所以只能擠掉5號元素 ) 輸出 a[ Myqueue[h] ]的值 -3

7、插入第7個數 Myqueue={ 6 7 } h=2; p=3 { 這裡為什麼4出列了?因為4到7已經不能被所給的範圍框住了...所以4要出列..然後繼續操作...因為7號元素比6號元素大...先排到後面) 輸出 a[ Myqueue[h] ]的值 3

8、插入第8個數 Myqueue={6 7 8 } h=2; p=4; { 因為8號元素比7號元素和6號元素都要大...所以放到後面... ) 輸出 a[ Myqueue[h] ]的值 3

還有一點要特別注意!!!如果後面的數和h[p]元素的數相等時...也要擠掉h[p]的....因為這個我WA了一次...囧....

這道題用單調佇列來跑只要5000MS..的確快了不少..但看大牛們還能更快...想知道怎麼做到的...

PS:...有個地方一定要注意...每次插入新數到佇列都要從隊尾往隊首掃..掃到比自己小的就確定位置..掃到比自大的就把這個大的數給擠掉.....如果從前往後掃....例如

1 2 3 4 5 6 7 8 9 ..... 很長一列...要插入一個很大的數...從前一直遍歷到最後面..才確定位置..這不是關鍵..關鍵是這一路過去..什麼操作都沒有做..白白掃了一大片空間...而從後往前掃...要麼確定位置...要麼踢到元素...總是在操作..所以必須要從後往前來判斷並插入....

Program :

[cpp] view plaincopyprint?
  1. /*
  2. POJ2823 - 單調佇列
  3. */
  4. #include<iostream>
  5. usingnamespace std;
  6. int n,m,a[1000001],Myqueue[1000001];
  7. void MinQueue()
  8. {
  9. int p=0,h=1,k,i;
  10. Myqueue[1]=1;
  11. for (k=1;k<=n;k++)
  12. {
  13. if (k-Myqueue[h]==m) h++;
  14. if (p==h-1 || a[k]>a[Myqueue[p]]){ p++; Myqueue[p]=k; }
  15. else
  16. {
  17. while (p>=h && a[k]<=a[Myqueue[p]]) { Myqueue[p]=k; p--; }
  18. p++;
  19. }
  20. if (k>=m) printf("%d ",a[Myqueue[h]]);
  21. }
  22. printf("\n");
  23. }
  24. void MaxQueue()
  25. {
  26. int p=0,h=1,k,i; Myqueue[1]=1;
  27. for (k=1;k<=n;k++)
  28. {
  29. if (k-Myqueue[h]==m) h++;
  30. if (p==h-1 || a[k]<a[Myqueue[p]]){ p++; Myqueue[p]=k; }
  31. else
  32. {
  33. while (p>=h && a[k]>=a[Myqueue[p]]) { Myqueue[p]=k; p--; }
  34. p++;
  35. }
  36. if (k>=m) printf("%d ",a[Myqueue[h]]);
  37. }
  38. printf("\n");
  39. }
  40. int main()
  41. {
  42. freopen("2823.in","r",stdin);
  43. freopen("2823T.out","w",stdout);
  44. scanf("%d%d",&n,&m);
  45. memset(a,0,sizeof(a));
  46. for (int i=1;i<=n;i++) scanf("%d",&a[i]);
  47. MinQueue();
  48. MaxQueue();
  49. return 0;
  50. }