CodeForces

题目链接

题目大意

  你可以根据给出的字符串左右移动光标(在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;
} 
原文地址:https://www.cnblogs.com/shuitiangong/p/14449197.html