两个栈维护队列,两个队列维护栈小结

两个栈维护队列

直接上例题!!!

jzoj 2292. 【佛山市选2010】PPMM

一题多解,又是好题啊~~~
首先,这题空间卡得恨死,所以线段树什么的都死了。。。
然后呢竟然还有好多种解法,我偏偏要撞进线段树里。。。

\(solution1\) 用两个栈来维护队列

首先这是没有可减性的(就是不支持删除其中的任一元素)
一个向右,一个向左。
向右的支持插入,向左的支持删除。
对于每个栈都维护一个前缀\(max\)\(min\),这样答案可以立即得到。
然后的话如果删除的删完了,那就把插入的那个栈全部倒放到删除的这个栈中,顺便求\(max\)\(min\)
取反操作很容易弄。

\(code\)

#include <cstdio>
#include <algorithm>
#define N 2000010
#define ll long long
#define mem(x, a) memset(x, a, sizeof x)
#define mpy(x, y) memcpy(x, y, sizeof y)
#define fo(x, a, b) for (register int x = (a); x <= (b); x++)
#define fd(x, a, b) for (register int x = (a); x >= (b); x--)
#define go(x) for (int p = tail[x], v; p; p = e[p].fr)
using namespace std;
int Q, z[N], z1[N], top = 0, top1 = 0;
int val[N][2], val1[N][2];
bool ops = 0;
char s[7];

inline int read()
{
	int x = 0, f = 0; char c = getchar();
	while (c < '0' || c > '9') f = (c == '-') ? 1 : f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
	return f ? -x : x;
}

int main()
{
	freopen("pm.in", "r", stdin);
	freopen("pm.out", "w", stdout);
	Q = read();
	val[0][0] = val1[0][0] = -2147483647;
	val[0][1] = val1[0][1] = 2147483647;
	while (Q--)
	{
		scanf("%s", s + 1);
		if (s[1] == 'P')
		{
			if (s[2] == 'U')
			{
				z[++top] = read();
				if (ops) z[top] = -z[top];
				val[top][0] = max(val[top - 1][0], z[top]);
				val[top][1] = min(val[top - 1][1], z[top]);
			}
			else
			{
				if (! top && ! top1) continue;
				if (top1) {top1--; continue;}
				while (top)
				{
					z1[++top1] = z[top--];
					val1[top1][0] = max(val1[top1 - 1][0], z1[top1]);
					val1[top1][1] = min(val1[top1 - 1][1], z1[top1]);
				}
				top1--;
			}
		} 
		else
		{
			if (s[2] == 'I') ops = ! ops;
			else
			{
				if (! top && ! top1) continue;
				if (ops == 0) printf("%d\n", max(val[top][0], val1[top1][0]));
				else printf("%d\n", -min(val[top][1], val1[top1][1]));
			}
		}
	}
	return 0;
}

\(solution2\) 单调队列

我们可以用单调队列来维护。
也就是两个单调队列,一个维护\(min\),一个维护\(max\)存的是原队列中的位置!
然后呢我们插入的话直接按照单调队列插入即可。
删除呢就看看单调队列的最左边(如果不是被覆盖了就一定是\(l\)),然后看看是否需要删除。
剩下两个操作都很容易了。

\(DYDL's\) \(code\)

#include <cstdio>
#include <algorithm>
#include <climits>
#include <cstring>
#include <iostream>
// #include <ctime>
// #include <cmath>
// #include <map>
// #include <vector>
// #include <set>
// #include <string>
#define open_in(x) freopen(#x".in", "r", stdin)
#define open_out(x) freopen(#x".out", "w", stdout)
#define open_(x) freopen(#x".in", "w", stdout)
#define open(x) open_in(x); open_out(x)
#define mes(x, y) memset(x, y, sizeof(x))
#define mec(x, y) memcpy(x, y, sizeof(x))
#define fo(x, y, z) for (int (x) = (y); (x) <= (z); (x)++)
#define fd(x, y, z) for (int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N = 2000010;
const int M = 1e9 + 7;
// inline int Random(int a, int b) {return rand() % (b - a + 1) + a;}
template<class T>
inline T read(T &x) {
	int f = 1; char ch = getchar(); x = 0;
	while (ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar();}
	while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
	return x *= f;
}

int n, a[N], l, r, flag;
char c1, c2;
struct Queue {
	int arr[N], l, r;
	Queue() {l = 1, r = 0;}
	inline bool Empty() {return l > r;}
	inline int Back() {return arr[r];}
	inline int Front() {return arr[l];}
	inline void Push(int x) {arr[++r] = x;}
	inline void PopBack() {r--;}
	inline void PopFront() {l++;}
} Qmin, Qmax;
int main() {
//	open_in(PPMM);
	l = 1, r = 0; flag = 0;
	read(n);
	while (n--) {
		c1 = getchar(); c2 = getchar();
		if (c1 == 'P') {
			if (c2 == 'U') {
				/* PUSH */
				int x; read(x);
				if (flag) x = -x;
				a[++r] = x;
				while (!Qmin.Empty() && a[Qmin.Back()] >= x) Qmin.PopBack();
				Qmin.Push(r);
				while (!Qmax.Empty() && a[Qmax.Back()] <= x) Qmax.PopBack();
				Qmax.Push(r);
			} else {
				/* POP */
				scanf("P\n");
				if (l <= r) {
					if (Qmin.Front() == l) Qmin.PopFront();
					if (Qmax.Front() == l) Qmax.PopFront();
					l++;
				}
			}
		} else {
			if (c2 == 'A') {
				/* MAX */
				scanf("X\n");
				if (l <= r) {
					printf("%d\n", (flag ? -a[Qmin.Front()] : a[Qmax.Front()]));
				}
			} else {
				/* MINUS */
				scanf("NUS\n");
				flag ^= 1;
			}
		}
	}
	return 0;
}
posted @ 2020-02-06 14:46  jz929  阅读(251)  评论(0编辑  收藏  举报