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