题面:
第十二届蓝桥杯国赛括号线段树_编程题目
题意:
操作1 把区间括号翻转
操作2 查询最长合法括号序列序列从l开始
思路:
类似于区间合并的问题,对于每个区间我们记录左右最小最大前缀值,我们把(看作1,)看作-1,合法的括号序列满足于当前的sum=0且对于任意前缀都是>=0,那么满足二分性质,我们可以二分套线段树查询到从l开始满足前缀大于等于0的最大位置,然后如果下个位置的sum<0那么就是当前位置,但是会有可能是查询到n,然后后面没数了且sum>0,那么我们就要二分出第一个后缀最大值等于sum的位置。
调了一下午调的心累。。。
代码:

#include<bits/stdc++.h>
#define IL inline
#define x first
#define y second
typedef long long ll;
using namespace std;
const	int N=200010;
struct node{
	int l;
	int r;
	int lz;
	int sum;
	int lmax;
	int lmin;
	int rmax;
	int rmin;
}tr[N<<2]; 
string s;
int n;
int m;
void pushup(int u)
{
	tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
	tr[u].lmax=max(tr[u<<1].lmax,tr[u<<1|1].lmax+tr[u<<1].sum);
	tr[u].lmin=min(tr[u<<1].lmin,tr[u<<1].sum+tr[u<<1|1].lmin);
	tr[u].rmin=min(tr[u<<1|1].rmin,tr[u<<1|1].sum+tr[u<<1].rmin);
	tr[u].rmax=max(tr[u<<1|1].rmax,tr[u<<1|1].sum+tr[u<<1].rmax);
}
void update(node &u)
{
	swap(u.lmin,u.lmax);
	u.lmin*=-1;
	u.lmax*=-1;
	u.sum=-u.sum;
	swap(u.rmin,u.rmax);
	u.rmin*=-1;
	u.rmax*=-1;
}
void pushdown(int u)
{
	if(tr[u].lz)
	{
		tr[u<<1].lz^=1;
		tr[u<<1|1].lz^=1;
		update(tr[u<<1]);
		update(tr[u<<1|1]);
		tr[u].lz=0;
	}
}
void build(int u,int l,int r)
{
	tr[u]={l,r};
	if(l==r)
	{
		if(s[l]==')')
		{
			tr[u].sum=-1;
			tr[u].lmax=tr[u].lmin=-1;
			tr[u].rmax=tr[u].rmin=-1;
		}
		else
		{
			tr[u].sum=1;
			tr[u].lmax=tr[u].lmin=1;
			tr[u].rmax=tr[u].rmin=1;
		}
		
		return;
	}
	int mid=l+r>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}
void mdf(int u,int l,int r)
{
	if(tr[u].l>=l && tr[u].r<=r)
	{
		tr[u].lz^=1;
		
		update(tr[u]);
		return ;
	}
	pushdown(u);
	int mid=tr[u].l+tr[u].r>>1;
	if(l<=mid)
	mdf(u<<1,l,r);
	if(r>mid)
	mdf(u<<1|1,l,r);
	pushup(u);
}
int querysum(int u,int l,int r)
{
	if(tr[u].l>=l && tr[u].r<=r)
	return tr[u].sum;
	pushdown(u);
	int mid=tr[u].l+tr[u].r>>1;
	int sum=0;
	if(l<=mid)	sum+=querysum(u<<1,l,r);
	if(r>mid)	sum+=querysum(u<<1|1,l,r);
	
	return sum;
}
int querymax(int u,int l,int r)
{
	if(tr[u].l>=l  && tr[u].r<=r)	
	return tr[u].rmax;
	pushdown(u);
	int mid=tr[u].l+tr[u].r>>1;
	int maxv=0;
	if(r<=mid) 	return querymax(u<<1,l,r);
	else if(l>mid)	return querymax(u<<1|1,l,r);
	else
	{
		int dd=querysum(u<<1|1,l,r);
		int td=querymax(u<<1,l,r);
		int td2=querymax(u<<1|1,l,r);
		return max(td2,td+dd);
	}
	
	

}
int query(int u,int l,int r)
{
	if(tr[u].l>=l && tr[u].r<=r)
	return tr[u].lmin;
	pushdown(u);
	int mid=tr[u].l+tr[u].r>>1;
	if(r<=mid)
		return query(u<<1,l,r);
	else if(l>=mid+1)
	return query(u<<1|1,l,r);
	else
	{
		int a=query(u<<1,l,r);
		int b=query(u<<1|1,l,r);
		return min(a,querysum(u<<1,l,r)+b);
	}
}
int main()
{
	cin >> n >> m;
	cin >> s;
	s = " "+s;
	build(1,1,n);
	//cout<<query(1,2,7)<<endl;
	//cout<<query(1,3,4)<<endl;
	while(m--)
	{
	
	
		int op;
		cin >> op;
		if(op==2)
		{
			int x;
			cin >> x;
			int l=x,r=n;
		//	if(x==6)
		//	cout<<"!"<<query(1,6,7)<<endl;
		int ans=0;
			while(l<r)
			{
				int mid=l+r+1>>1;
			//	cout<<query(1,x,mid)<<endl;
				if(query(1,x,mid)>=0)	l=mid;
				else	r=mid-1;
			}
			int tt=query(1,x,l);
			//cout<<" ->"<<l<<" "<<tt<<endl;
			int ansl=l;
			int sum=querysum(1,x,n);
		
			if(tt!=0)
			{
				cout<<0<<endl;
				continue;
			}
		
			if(ansl==n && sum)
			{
				//cout<<"--"<<endl;
				l=x;
				r=n;
				while(l<r)
				{
					int mid=l+r+1>>1;
					if(querymax(1,mid,n)>=sum) 	l=mid;
					else	r=mid-1;
				}
				cout<<r-1<<endl;
			}
			else
			cout<<l<<endl;
		}
		else
		{
			int l,r;
			cin >> l >> r;
			mdf(1,l,r);
		}
//			for(int j=1;j<=n;j++)
//			if(query(1,j,j)==1)
//				cout<<"(";
//				else if(query(1,j,j)==-1)
//				cout<<")";
//				cout<<endl;
	}
    return 0;
}

/*
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1


3
4
(((
2 3
1 2 3
1 1 2
2 2



8
9
)(((((((
1 2 4
1 3 4
2 1
1 5 5
1 7 7
1 3 6
1 4 6
2 6
2 1



12
6
())((()()()(
2 6
1 1 8
1 7 11
2 2
1 3 8
2 10
*/