题目链接
题意:给定一个括号字符串,给定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);
}
}