題目鏈接:
題目
請實現一個隊列,支持如下四種操作。
:將整數X加入到隊尾。
:將隊首的數字出隊。
:隊列中所有數字都變爲其相反數,即。
:返回隊列中最大的數。
對於操作、和,如果隊列爲空,則直接忽略它們。
現在給定一個操作序列,對於其中的每個操作,如果它沒有被忽略,請輸出它所返回的數。
輸入
輸入第一行爲正整數,表示操作的個數。
接下來行,每行爲一個操作。所有操作都用大寫字母表示。操作後會接着一個正整數。
輸出
對於每個沒有被忽略的操作,輸出其返回的數字,每個數字各佔一行。
樣例輸入
6
PUSH -2
MINUS
PUSH -1
MAX
POP
MAX
樣例輸出
2
-1
數據範圍
對於的數據有
對於的數據有
對於的數據有
思路
這道題其實就是模擬。
我們就建兩個數列(因爲有相反數),一個從小到大,一個從大到小。
每一次讀入的時候,就一定要插入這個數,然後就把前面不行的踢出去。
這樣, 我們操作的時候,就可以直接彈。
(如果序列第一個數就是要彈出的那個數,就彈出頭,不然就不彈出,因爲可能之前維護序列的時候已經彈出去了)
(因爲只要輸出,所以就可以在讀入的時候就把一定永遠不是答案的數彈出去)
因爲有變成相反數的操作,所以要用兩個序列。
具體看代碼吧。
代碼
#include<cstdio>
#define max(x, y) (x) > (y) ? (x) : (y)
using namespace std;
int m, x, n, nn, ma[2000001], mi[2000001], a[2000001];
int head1 = 1, head2 = 1, tail1, tail2, start = 1, end;
bool turn;
char c;
int main() {
scanf("%d", &m);//讀入
for (int i = 1; i <= m; i++) {
c = getchar();//讀入
while (c < 'A' || c > 'Z') c = getchar();//處理其他符號
if (c == 'P') {
c = getchar();//讀入
if (c == 'U') {//PUSH操作
getchar();
getchar();
scanf("%d", &x);//讀入
if (!turn) {//變相反數的次數是否爲雙數(即時候有變相反數)
a[++end] = x;//正常記錄
while (head1 <= tail1 && a[ma[tail1]] <= x) tail1--;//維護一個從大到小的序列
while (head2 <= tail2 && a[mi[tail2]] >= x) tail2--;//再維護一個從小到大的(因爲有時會是相反數)
ma[++tail1] = end;//加入序列中
mi[++tail2] = end;//兩個序列都要加入
}
else {//已經是變成了相反數的狀態
a[++end] = -x;//相反記錄
while (head1 <= tail1 && -a[ma[tail1]] >= x) tail1--;//如上同理
while (head2 <= tail2 && -a[mi[tail2]] <= x) tail2--;//因爲已經是相反數狀態,所以判斷大小時要相反
ma[++tail1] = end;//如上同理
mi[++tail2] = end;
}
}
else {//POP操作
getchar();
if (start > end) continue;//這個POP操作無效(隊列中沒有輸)
if (ma[head1] == start) head1++;//這個序列的頭要被彈出
if (mi[head2] == start) head2++;//跟上面一樣,只是是另外一個序列
start++;
}
}
else if (c == 'M') {
c = getchar();
if (c == 'I') {//MINUS操作
getchar();
getchar();
getchar();
if (start > end) continue;//隊列中沒有數,用了等於沒用
if (!turn) turn = 1;//之前不是相反數狀態,就變成相反數狀態
else turn = 0;//之前是相反數狀態,就變成正常的狀態
}
else {//MAX操作
getchar();
if (start > end) continue;
if (!turn) printf("%d\n", a[ma[head1]]);
else printf("%d\n", -a[mi[head2]]);
}
}
}
return 0;
}