题意:给你一串指令集,当某个指令为$L$时,表示鼠标的光标向左移动一个单位$($如果已经位于最左边,则不移动$)$,当指令为$R$时,表示将光标像右移动一个单位,其他的字符$($只有小写字母和左括号、右括号$)$都表示将当前光标指向的字符更改为输入的字符,对于每个指令,输出一个数,如果所得到的文本中括号序列合法,则是输出当前文本最大的括号嵌套层数,括号序列不合法则输出$-1$

思路:用$1$表示左括号,$-1$表示右括号,$0$表示其他字符,用一个线段树维护三个值:区间和$w$,区间最大前缀和$imax$,区间最小前缀和$imin$。对于任意一个合法的括号序列,需要满足以下两个条件:

  • 左括号和右括号的数量相等,即$w=0$
  • 括号序列的任意前缀和都大于等于$0$,即$imin \ge 0$

而对于一个合法的括号序列,括号的最大嵌套层数就是区间最大前缀和$imax$,需要维护一个单点修改和区间查询的线段树,但由于每次查询的区间都是$[1,n]$,线段树根节点表示的区间正好是$[1,n]$,所以只用维护一个单点修改的线段树,输入小写字母和左括号、右括号时,将光标位置上的值改为对应的值,同时更新区间和,区间最大前缀和,区间最小前缀和,具体更新如下:

  • 区间和$=$左区间和$+$右区间和
  • 最小前缀和$=min($左区间最小前缀和$,$左区间区间和$+$右区间最小前缀和$)$
  • 最大前缀和$=max($左区间最大前缀和$,$左区间区间和$+$右区间最大前缀和$)$

更新后判断$[1,n]$的括号序列是否合法,不合法输出$-1$,合法则直接输出区间$[1,n]$中$imax$的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

const int N = 1000010;

struct node {
int l, r, w;
int imin, imax;
};

node tree[4 * N];
int n, res[N];
char s[N];

void build(int k, int lef, int rig)
{
tree[k].l = lef, tree[k].r = rig;
if (tree[k].l == tree[k].r) {
tree[k].w = tree[k].imin = tree[k].imax = 0;
return;
}
int mid = (lef + rig) / 2;
build(k * 2, lef, mid);
build(k * 2 + 1, mid + 1, rig);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
tree[k].imax = max(tree[k * 2].imax, tree[k * 2 + 1].imax);
tree[k].imin = max(tree[k * 2].imin, tree[k * 2 + 1].imin);
}

void change_point(int k, int x, int y)
{
if (tree[k].l == tree[k].r) {
tree[k].w = y;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (x <= mid) change_point(2 * k, x, y);
else change_point(2 * k + 1, x, y);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
tree[k].imax = max(tree[k * 2].imax, tree[k * 2].w + tree[k * 2 + 1].imax);
tree[k].imin = min(tree[k * 2].imin, tree[k * 2].w + tree[k * 2 + 1].imin);
}

int main()
{
scanf("%d%s", &n, s + 1);
build(1, 1, n);
int cur = 1, len = strlen(s + 1);
for (int i = 1; i <= len; i++) {
if ('(' == s[i]) change_point(1, cur, 1);
else if (')' == s[i]) change_point(1, cur, -1);
else if ('L' == s[i]) {
if (cur >= 2) cur--;
}
else if ('R' == s[i]) cur++;
else change_point(1, cur, 0);
if (0 != tree[1].w || 0 != tree[1].imin) res[i] = -1;
else res[i] = tree[1].imax;
}
for (int i = 1; i <= len; i++) {
printf("%d", res[i]);
printf(i == len ? "\n" : " ");
}
return 0;
}