题目大意:
维护一个光标,支持多个操作:
①
I
I
,在光标位置前插入一个数x
②
D
D
,删除当前光标位置前一个数。
③,光标左移直至不能移动为止。
④
R
R
,光标右移直至不能移动为止。
⑤
x
x
,查询前x个数的前缀和的最大值。
操作数有个。
1≤|x|≤103
1
≤
|
x
|
≤
10
3
1≤Q≤106
1
≤
Q
≤
10
6
分析:
维护
2
2
个栈,
1个Sum[]维护栈A的前缀和
1
个
S
u
m
[
]
维
护
栈
A
的
前
缀
和
,
1个f[]维护栈A的前缀和的最大值
1
个
f
[
]
维
护
栈
A
的
前
缀
和
的
最
大
值
A
A
存储[序列开头,当前光标位置]的一段子序列。
倒着存储序列[当前光标位置+1,序列结尾]的一段子序列。
对于操作
I
I
,
我们将
我
们
将
x
插入栈A中,在栈A中位置为y
插
入
栈
A
中
,
在
栈
A
中
位
置
为
y
,此时
y
y
为栈顶位置
f[y]=max(f[y−1],Sum[y])
f
[
y
]
=
m
a
x
(
f
[
y
−
1
]
,
S
u
m
[
y
]
)
对于操作
D
D
,
弹出A的栈顶即可
对于操作,
弹出A的栈顶然后插入到B中即可。
对于操作
R
R
,
弹出的栈顶,插入到
A
A
中,
然后类似于
x
x
的操作,维护
对于操作
Q
Q
,
回答
f[x]
f
[
x
]
,
O(1)
O
(
1
)
得到。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define N 1000005
using namespace std;
int Sum[N], A[N], B[N], f[N];
int Q, x, l, r;
char c[2];
int main() {
while (~scanf("%d", &Q)) {
l = r = 1;
while (Q--) {
scanf("%s", c);
switch (c[0]) {
case 'D':
if (l > 1) l--;
break;
case 'I':
scanf("%d", &x);
A[l++] = x;
if (l == 2) Sum[1] = f[1] = x;
else {
Sum[l - 1] = Sum[l - 2] + x;
f[l - 1] = max(f[l - 2], Sum[l - 1]);
}
break;
case 'L':
if (l > 1) B[r++] = A[--l];
break;
case 'Q':
scanf("%d", &x);
printf("%d\n", f[x]);
break;
case 'R':
if (r > 1) {
x = B[--r];
A[l++] = x;
if (l == 2) Sum[1] = f[1] = x;
else {
Sum[l - 1] = Sum[l - 2] + x;
f[l - 1] = max(f[l - 2], Sum[l - 1]);
}
}
break;
}
}
}
return 0;
}