Alice 給 Bob 佈置了不少工做,他忙的不可開交,決定按照「先進先出(FIFO)」的順序依次處理這些工做。可是處理過程當中,Bob 意識到這種順序可能不是最優的,所以他會選擇性的把某些工做延後。html
抽象來講,你須要維護一個隊列,支持三種操做:c++
操做一:1 v,在隊尾加入一個價值爲 v 的任務。數組
操做二:2,若是當前隊列爲空,輸出 -1;不然輸出隊頭任務的價值,並將隊頭彈出。ide
操做三:3,若是當前隊列爲空,則不進行任何操做;不然將隊列中價值最小的任務挪到隊尾,保證沒有價值相等的任務。spa
輸入格式:code
第一行一個整數 n,表示操做個數。htm
接下來 n 行,每行一個或兩個整數,格式如上。blog
輸出格式:隊列
對於每一個操做 2,輸出答案。it
2 1 -1
【題解】:
聽過講解以後,發現這個想法很是有趣。
其實Push,Pop通常隊列均可以維護,可是對於Mov操做就須要你們開動一下腦筋了。
其實Mov不必定須要移動。須要的是標記,最小值標記,而後用Set來查找最小值的位置,
而後Push進去的歷史編號。
獲得的Val[No] 用數組來保存歷史編號的值便可。
Push( ) 進入隊列不單單是隊列,還有Set。
Pop( ) 彈出時注意,有些用Mov標記的可能出如今隊頭,記得要把它彈出。
Mov( )操做涉及到兩個問題。
第一個:用Set的頭元素即爲最小值的,同時Set存的是pair類型,
第一關鍵字是:權值,val,第二關鍵字爲:歷史編號 ,No
Set直接找到對應的歷史編號進行標記。
同時在Set刪除,而後對於隊列來講,從新Push進去一個val值。
附上代碼:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N = 3e5+100; 4 queue <int> Q ; 5 set< pair<int,int> > S; 6 int cur ,val[N] , top ; 7 bool deleted[N]; 8 void push( int v ){ 9 cur ++ ; 10 val[cur] = v; 11 Q.push(cur); 12 S.insert( make_pair(v,cur) ); 13 } 14 int pop(){ 15 if( S.empty() ) return -1; 16 while( deleted[Q.front()] ){ 17 Q.pop(); 18 } 19 int ret = Q.front(); 20 Q.pop(); 21 S.erase( make_pair(val[ret],ret) ); 22 return val[ret]; 23 } 24 void mov(){ 25 if( S.empty() ) return ; 26 deleted[S.begin()->second] = true ; 27 push(val[S.begin()->second]); 28 S.erase( S.begin() ); 29 } 30 int main() 31 { 32 int n,opt,v; 33 scanf("%d",&n); 34 while(n--){ 35 scanf("%d",&opt); 36 if( opt == 1 ){ 37 scanf("%d",&v); 38 push(v); 39 }else if( opt == 2 ){ 40 printf("%d\n",pop()); 41 }else{ 42 mov(); 43 } 44 } 45 return 0; 46 }