两个栈维护队列
直接上例题!!!
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
", max(val[top][0], val1[top1][0]));
else printf("%d
", -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
");
if (l <= r) {
if (Qmin.Front() == l) Qmin.PopFront();
if (Qmax.Front() == l) Qmax.PopFront();
l++;
}
}
} else {
if (c2 == 'A') {
/* MAX */
scanf("X
");
if (l <= r) {
printf("%d
", (flag ? -a[Qmin.Front()] : a[Qmax.Front()]));
}
} else {
/* MINUS */
scanf("NUS
");
flag ^= 1;
}
}
}
return 0;
}