【GMOJ2292】PPMM

前言

今天3道题都卡常。。。都吸了氧才过。。。

题目

题目链接:
请实现一个队列,支持如下四种操作。
PUSH X:将整数X加入到队尾。
POP:将队首的数字出队。
MINUS:队列中所有数字都变为其相反数,即X←-X。
MAX:返回队列中最大的数。
对于操作POP、MINUS和MAX,如果队列为空,则直接忽略它们。
现在给定一个操作序列,对于其中的每个MAX操作,如果它没有被忽略,请输出它所返回的数。

思路

对于\(\rm PUSH,POP,MAX\)操作都是堆的基础操作。维护一个大根堆和一个删除堆即可。
容易发现,\(\rm MINUS\)操作将队列的数字变为其相反数,相当于将后面才加入队列的数取相反数,然后\(\rm MAX\)操作时取最小值的相反数。
那么在维护一个小根堆和一个小根删除堆即可。
时间复杂度\(O(n\log n)\)

代码

#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include <queue>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=2000010;
int n,head,tail,a[N];
bool flag;
char ch[10];
priority_queue<int> qs,qb,delb,dels;

int read()
{
	int d=0,f=1; char ch=getchar();
	while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
	return d*f;
}

int main()
{
	n=read();
	head=1;
	while (n--)
	{
		scanf("%s",ch);
		if (ch[1]=='U')
		{
			a[++tail]=read();
			if (flag) a[tail]=-a[tail];
			qb.push(a[tail]); qs.push(-a[tail]);
		}
		if (ch[1]=='O')
			if (head<=tail)
			{
				delb.push(a[head]);
				dels.push(-a[head]);
				head++;
			}
		if (ch[1]=='I') flag^=1;
		if (ch[1]=='A')
		{
			if (head>tail) continue;
			if (!flag)
			{
				while (qb.size() && delb.size() && qb.top()==delb.top())
					qb.pop(),delb.pop();
				printf("%d\n",qb.top());
			}
			else
			{
				while (qs.size() && dels.size() && qs.top()==dels.top())
					qs.pop(),dels.pop();
				printf("%d\n",qs.top());
			}
		}
	}
	return 0;
}
posted @ 2020-02-06 16:25  stoorz  阅读(338)  评论(0编辑  收藏  举报