题目链接:
题目
请实现一个队列,支持如下四种操作。
:将整数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;
}