题意:给你一串指令集,当某个指令为$``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$的值
#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 ? " " : " "); } return 0; }