PPMM

PPMMPPMM

題目鏈接:jozj 2292jozj\ 2292

題目

請實現一個隊列,支持如下四種操作。
PUSH XPUSH\ X:將整數X加入到隊尾。
POPPOP:將隊首的數字出隊。
MINUSMINUS:隊列中所有數字都變爲其相反數,即X ⁣ ⁣ ⁣ ⁣XX\!\!←\!-\!X
MAXMAX:返回隊列中最大的數。
對於操作POPPOPMINUSMINUSMAXMAX,如果隊列爲空,則直接忽略它們。
現在給定一個操作序列,對於其中的每個MAXMAX操作,如果它沒有被忽略,請輸出它所返回的數。

輸入

輸入第一行爲正整數NN,表示操作的個數。
接下來NN行,每行爲一個操作。所有操作都用大寫字母表示。PUSHPUSH操作後會接着一個正整數XX

輸出

對於每個沒有被忽略的MAXMAX操作,輸出其返回的數字,每個數字各佔一行。

樣例輸入

6
PUSH -2
MINUS
PUSH -1
MAX
POP
MAX

樣例輸出

2
-1

數據範圍

231 ⁣ ⁣< ⁣ ⁣X ⁣ ⁣< ⁣ ⁣231-2^{31}\! \!<\! \!X\! \!<\! \!2^{31}
對於20%20\%的數據有 N ⁣ ⁣ ⁣ ⁣100N\! \!≤\! \!100
對於50%50\%的數據有 N ⁣ ⁣ ⁣ ⁣10, ⁣000N\! \!≤\! \!10,\!000
對於100%100\%的數據有 N ⁣ ⁣ ⁣ ⁣2, ⁣000, ⁣000N\! \!≤\! \!2,\!000,\!000

思路

這道題其實就是模擬。

我們就建兩個數列(因爲有相反數),一個從小到大,一個從大到小。
每一次讀入的時候,就一定要插入這個數,然後就把前面不行的踢出去。
這樣, 我們POPPOP操作的時候,就可以直接彈。
(如果序列第一個數就是要彈出的那個數,就彈出頭,不然就不彈出,因爲可能之前維護序列的時候已經彈出去了)
(因爲只要輸出MAXMAX,所以就可以在讀入的時候就把一定永遠不是答案的數彈出去)
因爲有變成相反數的操作,所以要用兩個序列。

具體看代碼吧。

代碼

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章