Codeforces Round #223 (Div. 1) C. Sereja and Brackets(线段树+思维)

题目链接
在这里插入图片描述
题意:给定一个括号字符串,给定m个询问,每次询问一个区间【l,r】的最大括号匹配数量是多少。
思路:很考验思维量的一个题目,在用线段树维护左右括号的做发遇到了bug果断放弃了,这个方法好是好,但难想啊。。。
L【i】表示的是1-i还未匹配的左括号数量,R【i】表示1-i中右括号的数量,现在给你一个区间【l,r】,我们知道最大数量肯定是R【r】-R【l-1】(显示这是理想状态,几乎达不到),它肯定还得减去【l,r】中未匹配的右括号才行,那么怎么求呢?就用到了L数组,【l,r】中未匹配的右括号的数量就等于L【l-1】-min(L【l。。。。r】),min(L【l。。。。r】可以用线段树来维护。

#include <bits/stdc++.h>
using namespace std;
const int maxn= 1e6+10;
char s[maxn];
int L[maxn],R[maxn];
struct node{
	int l,r,sum;
}tree[maxn<<2];
void pushup(int x)
{
	tree[x].sum=min(tree[x<<1].sum,tree[x<<1|1].sum);
}
void build(int x,int l,int r)
{
	tree[x].l=l;tree[x].r=r;
	if(l==r)
	{
		tree[x].sum=L[l];
		return ;
	}
	int mid=(l+r)>>1;
	build(x<<1,l,mid);
	build(x<<1|1,mid+1,r);
	pushup(x);
}
int query(int x,int l,int r)
{
	if(l<=tree[x].l&&tree[x].r<=r) return tree[x].sum;
	int mid=(tree[x].l+tree[x].r)>>1;
	if(r<=mid) return query(x<<1,l,r);
	else if(l>mid) return query(x<<1|1,l,r);
	else return min(query(x<<1,l,mid),query(x<<1|1,mid+1,r));
	pushup(x);
}
int main()
{
	scanf("%s",s+1);
	int len=strlen(s+1),temp=0,q,l,r;
	for(int i=1;i<=len;++i)
	{
		R[i]=R[i-1];
		if(s[i]=='(') temp++;
		else R[i]++,temp--;
		L[i]=temp;
	}
	build(1,1,len);
	scanf("%d",&q);
	while(q--)
	{
		scanf("%d %d",&l,&r);
		printf("%d\n",(R[r]-R[l-1]-max(L[l-1]-query(1,l,r),0))*2);
	}
}
发布了283 篇原创文章 · 获赞 0 · 访问量 7304

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105075684