题目大意
你可以根据给出的字符串左右移动光标(在1处不向左移动),还可以在当前光标处输入(或修改)'(',')'和普通字符,问当前的字符串是否是一个合法的括号序列,如果是,问括号最多嵌套的有多少层。
解题思路
我们知道括号序列问题可以把左括号当成+1,右括号-1,这样总和是0,中间过程没有出现负数的序列就是一个合法序列,而中间的最大值就是括号的最大嵌套数。这个问题相当的在某个位置+1或者-1,然后询问其前缀和的最大值,最小值,以及总和。简单的说就是一个动态维护前缀和的过程,用线段树很容易解决。
代码
const int maxn = 1e6+10;
const int maxm = 2e5+10;
char str[maxn], res[maxn];
int n;
struct I {
ll sum, maxx, minn, lz;
} tree[maxn<<2];
inline void push_down(int rt, int len) {
if (tree[rt].lz) {
I &ls = tree[rt<<1];
I &rs = tree[rt<<1|1];
ll lz = tree[rt].lz;
ls.lz += lz;
ls.sum += len/2*lz;
ls.maxx += lz;
ls.minn += lz;
rs.lz += lz;
rs.sum += (len/2+1)*lz;
rs.maxx += lz;
rs.minn += lz;
tree[rt].lz = 0;
}
}
inline void push_up(int rt) {
tree[rt].maxx = max(tree[rt<<1].maxx, tree[rt<<1|1].maxx);
tree[rt].minn = min(tree[rt<<1].minn, tree[rt<<1|1].minn);
tree[rt].sum = tree[rt<<1].sum+tree[rt<<1|1].sum;
}
void update(int rt, int l, int r, int a, int b, int val) {
if (l>=a && r<=b) {
tree[rt].lz += val;
tree[rt].sum += (r-l+1)*val;
tree[rt].maxx += val;
tree[rt].minn += val;
return;
}
push_down(rt, r-l+1);
int mid = (l+r)>>1;
if (a<=mid) update(rt<<1, l, mid, a, b, val);
if (b>mid) update(rt<<1|1, mid+1, r, a, b, val);
push_up(rt);
}
int main() {
cin >> n >> str+1;
int p = 1, tot = 0;
for (int i = 1; i<=n; ++i) {
if (str[i]=='R') ++p;
else if (str[i]=='L') {
if (p!=1) --p;
}
else {
if (res[p]=='(') update(1, 1, n, p, n, -1), --tot;
else if (res[p]==')') update(1, 1, n, p, n, 1), ++tot;
res[p] = str[i];
if (res[p]=='(') update(1, 1, n, p, n, 1), ++tot;
else if (res[p]==')') update(1, 1, n, p, n, -1), --tot;
}
if (tree[1].minn < 0 || tot) printf(i==n ? "%d
":"%d ", -1);
else printf(i==n ? "%d
":"%d ", tree[1].maxx);
}
return 0;
}