题解:CF380C Sereja and Brackets

居然让我一遍过了......

Pro

查询区间内最长合法序列。

Sol

定义 w1uw1_u 表示不可匹配左括号,w2uw2_u 同理。

那么考虑如何从 w1lw1_lw1rw1_r 推出 w1uw1_u

最容易想到的是 w1u=w1l+w1rw1_u=w1_l+w1_r,但是作为一道不是板子题的题,怎么可能这么简单?

容易发现,我们遗漏了两边括号可以合并的括号对,这里一共有 min{w1l,w2r}\min\{w1_l,w2_r\}

所以 w1u=w1l+w2rmin{w1l,w2r}w1_u=w1_l+w2_r-\min\{w1_l,w2_r\}

然后查询时用同样的套路即可。

Code

#include<bits/stdc++.h>
using namespace std;
int n;
struct Segment_tree{
	string s;
	int w1[4*1000005],w2[4*1000005];
	void pushup(int u)
	{
		w1[u]=w1[u*2]+w1[u*2+1]-min(w1[u*2],w2[u*2+1]);
		w2[u]=w2[u*2]+w2[u*2+1]-min(w1[u*2],w2[u*2+1]);
	}
	void build(int u=1,int l=1,int r=n)
	{
		if(l==r)
		{
			w1[u]=(s[l]=='(');
			w2[u]=(s[l]==')');
			return;
		}
		int mid=(l+r)/2;
		build(u<<1,l,mid);
		build(u<<1|1,mid+1,r);
		pushup(u);
	}
	bool InRangeOf(int L,int R,int l,int r)
	{
		return (l<=L)&&(R<=r);
	}
	bool OutRangeOf(int L,int R,int l,int r)
	{
		return (L>r)||(R<l);
	}
	pair<int,int> query(int l,int r,int u=1,int L=1,int R=n)
	{
		if(InRangeOf(L,R,l,r)) return make_pair(w1[u],w2[u]);
		else if(!OutRangeOf(L,R,l,r))
		{
			int mid=(L+R)/2;
			pair<int,int> ls=query(l,r,u*2,L,mid),
						  rs=query(l,r,u*2+1,mid+1,R);
			return make_pair((ls.first+rs.first-min(ls.first,rs.second)),(ls.second+rs.second-min(ls.first,rs.second)));
		}
		else return make_pair(0,0);
	}
}a;
int main()
{
	cin>>a.s;
	n=a.s.size();
	a.s=" "+a.s;
	a.build();
	int q;
	cin>>q;
	while(q--)
	{
		int l,r;
		cin>>l>>r;
		cout<<(r-l+1-a.query(l,r).first-a.query(l,r).second)<<endl;
	}
	return 0;
}
posted @ 2024-11-13 16:17  sLMxf  阅读(14)  评论(0)    收藏  举报  来源