题目链接: Editor
大致题意
给出一系列操作, 问每次操作结束后, 括号能否正确匹配. 若可以, 则输出最大匹配深度, 否则输出-1.
解题思路
线段树 很经典的线段树区间合并处理括号匹配问题.
关于线段树的括号匹配问题, 目前我知道的有两种: 一种是询问正确匹配括号个数, 另外一种是询问能否成功匹配, 以及匹配最大深度问题.
对于一个区间而言, 括号能否成功匹配有两个判断标准:
①左右括号数量要相同
②任意前缀中, 右括号的数目不能大于左括号的数目.
如果我们把左括号看为+1, 右括号看为-1, 则上述标准等价于:
① 区间和为0
② 区间最小前缀和也应等于0
此时最大匹配深度应是区间最大连续子段和. 假设区间可以正确匹配, 则前缀和不会出现负数情况, 因此最大连续子段和等价于最大前缀和. 我们只需要维护最大前缀和即可.
因此对于这类问题, 我们只需要维护区间最大前缀和, 最小前缀和, 区间和三个信息即可.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
int fact(char c) {
if (c == '(') return 1;
if (c == ')') return -1;
return 0;
}
struct node {
int l, r;
int sum, fmax, fmin;
}t[N << 2];
void pushup(node& p, node& l, node& r) {
p.sum = l.sum + r.sum;
p.fmax = max(l.fmax, l.sum + r.fmax);
p.fmin = min(l.fmin, l.sum + r.fmin);
}
void pushup(int x) { pushup(t[x], t[x << 1], t[x << 1 | 1]); }
void build(int l, int r, int x = 1) {
t[x] = { l, r, 0, 0, 0 };
if (l == r) return;
int mid = l + r >> 1;
build(l, mid, x << 1), build(mid + 1, r, x << 1 | 1);
}
void modify(int a, int c, int x = 1) {
if (t[x].l == t[x].r) {
t[x].fmax = t[x].fmin = t[x].sum = c;
return;
}
int mid = t[x].l + t[x].r >> 1;
modify(a, c, x << 1 | (a > mid));
pushup(x);
}
char s[N];
int main()
{
int n; cin >> n >> s + 1;
build(1, n);
int pos = 1;
rep(i, n) {
if (s[i] == 'L') pos = max(1, pos - 1);
else if (s[i] == 'R') pos = pos + 1;
else modify(pos, fact(s[i]));
int res = t[1].fmax;
if (t[1].sum or t[1].fmin < 0) res = -1;
printf("%d%c", res, " \n"[i == n]);
}
return 0;
}