Codeforces1263E Editor (线段树 + 括号序列)

题目链接: 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;
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值