FZU 1978 Repair the brackets

Description

A regular bracket sequence is defined as follows:

1. Empty sequence is a regular bracket sequence.2. If S is a regular bracket sequence, then (S) is also a regular bracket sequence.3. If a and b are regular bracket sequences, then ab is a regular bracket sequence.4. Any other sequences are not regular bracket sequences.

Given a bracket sequence S of size N consisting of '(' and ')'. Each time you should simulate one of the following operations:

1. Replace f r c: Replace all brackets by c in [f, r].2. Swap f r: Reverse all brackets in [f, r].3. Invert f r: Invert all brackets in [f, r] from '(' to ')' and vice versa.4. Query f r: Output the minimum changes to repair the brackets in [f, r] intoa regular bracket sequence. To repair the brackets each time you can invert abracket from '(' to ')' or vice versa. For example, you need 2 changes to repair "((((" to "(())" by inverting the last two '(' to ')'. The length of the query sequence, that is r-f+1, will always be even. You should note that f and r will fit 1≤f≤r≤N, c is either '(' or ')'.

Input

In the first line there is an integer T (T≤50), indicates the number of test cases. Each case begins with a line containing two integers N (1≤N≤50,000) and M (1≤M≤50,000), the size of the initial brackets sequence and the number of queries. The next line contains N characters consisting of '(' and ')'. Each of the following M lines contains one operation as said above. The index of the bracket sequence is labeled from 1 to N.

Output

For each test case, print a line containing the test case number (beginning with 1) on its own line, then the minimum changes to repair the brackets in [f, r] into a regular brackets sequence for each "Query" operation, one on each line.

Sample Input

4
2 2
((
Invert 1 2
Query 1 2
3 1
(()
Invert 1 3
8 4
)))()()(
Invert 6 7
Swap 3 6
Replace 5 7 (
Query 4 7
9 3
(())()(()
Swap 1 7
Replace 8 9 (
Query 1 4

Sample Output

Case 1:

1

Case 2:

Case 3:

3

Case 4:

0

此题是继维修数列后的又一道splay维护难题,关键是如何求解最小花费合理括号序列,然后其他的都跟维修数列类似的做法,

然而即便如此,还是调试了半天才搞定,果然还是太弱啊。。。需要注意的是两个延迟标记之间的互相影响。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<iostream>
#include<algorithm>
#include<bitset>
#include<functional>
using namespace std;
typedef unsigned long long ull;
typedef long long LL;
const int maxn = 1e5 + 10;
int T, n, m, l, r, c, root;
char s[maxn];

struct Splays
{
	const static int maxn = 1e5 + 10;			//节点个数
	const static int INF = 0x7FFFFFFF;			//int最大值
	int ch[maxn][2], F[maxn], sz;				//左右儿子,父亲节点和节点总个数
	int A[maxn], C[maxn], S[maxn], L[maxn][2], R[maxn][2], Flag[maxn][3];
	int Node(int f, int a) {
		C[sz] = 1;  F[sz] = f;
		S[sz] = A[sz] = a;
		L[sz][0] = R[sz][0] = min(0, a);
		L[sz][1] = R[sz][1] = max(0, a);
		ch[sz][0] = ch[sz][1] = 0;
		memset(Flag[sz], 0, sizeof(Flag[sz]));
		return sz++;
	}//申请一个新节点
	void clear(){
		sz = 1;
		ch[0][0] = ch[0][1] = F[0] = 0;
		L[0][0] = R[0][0] = C[0] = 0;
		L[0][1] = R[0][1] = S[0] = 0;
		memset(Flag, 0, sizeof(Flag));
	}//清空操作
	void swapdown(int x)
	{
		Flag[x][1] ^= 1;
		swap(L[x][0], R[x][0]);
		swap(L[x][1], R[x][1]);
		swap(ch[x][0], ch[x][1]);
	}
	void invertdown(int x)
	{
		if (!Flag[x][0]) Flag[x][2] ^= 1;
		swap(L[x][0], L[x][1]);
		swap(R[x][0], R[x][1]);
		L[x][0] *= -1; L[x][1] *= -1;
		R[x][0] *= -1; R[x][1] *= -1;
		A[x] *= -1;	S[x] *= -1;
	}
	void replacedown(int x, int c)
	{
		Flag[x][0] = 1;	Flag[x][2] = 0;
		A[x] = c;	S[x] = C[x] * c;
		L[x][0] = R[x][0] = min(0, S[x]);
		L[x][1] = R[x][1] = max(0, S[x]);
	}
	void pushdown(int x)
	{
		if (Flag[x][0])
		{
			if (ch[x][0]) replacedown(ch[x][0], A[x]);
			if (ch[x][1]) replacedown(ch[x][1], A[x]);
		}
		if (Flag[x][1])
		{
			if (ch[x][0]) swapdown(ch[x][0]);
			if (ch[x][1]) swapdown(ch[x][1]);
		}
		if (Flag[x][2])
		{
			if (ch[x][0]) invertdown(ch[x][0]);
			if (ch[x][1]) invertdown(ch[x][1]);
		}
		memset(Flag[x], 0, sizeof(Flag[x]));
	}
	void count(int x)
	{
		C[x] = C[ch[x][0]] + C[ch[x][1]] + 1;
		S[x] = S[ch[x][0]] + S[ch[x][1]] + A[x];
		L[x][0] = min(L[ch[x][0]][0], S[ch[x][0]] + A[x] + L[ch[x][1]][0]);
		L[x][1] = max(L[ch[x][0]][1], S[ch[x][0]] + A[x] + L[ch[x][1]][1]);
		R[x][0] = min(R[ch[x][1]][0], S[ch[x][1]] + A[x] + R[ch[x][0]][0]);
		R[x][1] = max(R[ch[x][1]][1], S[ch[x][1]] + A[x] + R[ch[x][0]][1]);
	}
	void rotate(int x, int k)
	{
		int y = F[x]; ch[y][!k] = ch[x][k];
		if (ch[x][k]) F[ch[x][k]] = y;
		if (F[y]) ch[F[y]][y == ch[F[y]][1]] = x;
		F[x] = F[y];    F[y] = x;	ch[x][k] = y;
		C[x] = C[y];	S[x] = S[y];
		L[x][0] = L[y][0];  L[x][1] = L[y][1];
		R[x][0] = R[y][0];	R[x][1] = R[y][1];
		count(y);
	}
	void Splay(int x, int r)
	{
		while (F[x] != r)
		{
			if (F[F[x]] == r) { rotate(x, x == ch[F[x]][0]); return; }
			int y = x == ch[F[x]][0], z = F[x] == ch[F[F[x]]][0];
			y^z ? (rotate(x, y), rotate(x, z)) : (rotate(F[x], z), rotate(x, y));
		}
	}
	void build(int fa, int &x, int l, int r)
	{
		if (l > r) return;
		int mid = l + r >> 1;
		x = Node(fa, s[mid] == '(' ? 1 : -1);
		build(x, ch[x][0], l, mid - 1);
		build(x, ch[x][1], mid + 1, r);
		count(x);
	}
	void find(int &x, int k)
	{
		for (int i = x; i;)
		{
			pushdown(i);
			if (C[ch[i][0]] > k) { i = ch[i][0]; continue; }
			if (C[ch[i][0]] == k) { Splay(i, F[x]); x = i; break; }
			k -= C[ch[i][0]] + 1;	i = ch[i][1];
		}
	}
	int get(int &x, int l, int r)
	{
		find(x, l - 1);		find(ch[x][1], r - l + 1);
		return ch[ch[x][1]][0];
	}
	void Swap(int &x, int l, int r)
	{
		int g = get(x, l, r); swapdown(g);
		count(ch[x][1]);	count(x);
	}
	void Invert(int &x, int l, int r)
	{
		int g = get(x, l, r);  invertdown(g);
		count(ch[x][1]);	count(x);
	}
	void Replace(int &x, int l, int r, int c)
	{
		int g = get(x, l, r);	replacedown(g, c);
		count(ch[x][1]);	count(x);
	}
	void Query(int &x, int l, int r)
	{
		int g = get(x, l, r);
		printf("%d\n", (S[g] - L[g][0] + 1) / 2 + (1 - L[g][0]) / 2);
	}
}solve;


int main()
{
	cin >> T;
	for (int tt = 1; tt <= T; tt++)
	{
		solve.clear();	root = 0;
		scanf("%d%d%s", &n, &m, s + 1);
		s[0] = s[n + 1] = '(';
		solve.build(0, root, 0, n + 1);
		printf("Case %d:\n", tt);
		while (m--)
		{
			scanf("%s%d%d", s, &l, &r);
			if (s[0] == 'S') solve.Swap(root, l, r);
			if (s[0] == 'I') solve.Invert(root, l, r);
			if (s[0] == 'Q') solve.Query(root, l, r);
			if (s[0] == 'R') scanf("%s", s), solve.Replace(root, l, r, s[0] == '(' ? 1 : -1);
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值