题意:
给一个括号序列,q个询问
每个询问求[l,r]中最大合法括号序列长度
(注意是序列)
Examples
Input
())(())(())(
7
1 1
2 3
1 2
1 12
8 12
5 11
2 10
Output
0
0
2
10
4
6
6
思路:
线段树维护三个信息:
已经匹配的合法括号序列个数
多余的左括号个数
多余的右括号个数
pushup的时候左子树左括号个数和右子树右括号个数可以匹配
维护就行了
查询的时候因为要最多左边多余的左括号和右边多余的右括号和已经匹配的个数
总共有三个信息,所以查询的时候返回结构体
code:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxm=1e6+5;
struct Node{
int cnt;//已经匹配的合法括号个数
int l,r;//还未匹配的左括号和右括号个数
}a[maxm<<2];
int n,m;
char s[maxm];
void pushup(int node){
int temp=min(a[node*2].l,a[node*2+1].r);
a[node].cnt=a[node*2].cnt+a[node*2+1].cnt+temp;
a[node].l=a[node*2].l+a[node*2+1].l-temp;
a[node].r=a[node*2].r+a[node*2+1].r-temp;
}
void build(int l,int r,int node){
if(l==r){
if(s[l]=='(')a[node].l=1;
else a[node].r=1;
return ;
}
int mid=(l+r)/2;
build(l,mid,node*2);
build(mid+1,r,node*2+1);
pushup(node);
}
Node ask(int st,int ed,int l,int r,int node){
if(st<=l&&ed>=r){
return a[node];
}
int mid=(l+r)/2;
Node lc={0,0,0},rc={0,0,0},res={0,0,0};
if(st<=mid){
lc=ask(st,ed,l,mid,node*2);
}
if(ed>=mid+1){
rc=ask(st,ed,mid+1,r,node*2+1);
}
int temp=min(lc.l,rc.r);
res.cnt=lc.cnt+rc.cnt+temp;
res.l=lc.l+rc.l-temp;
res.r=lc.r+rc.r-temp;
return res;
}
int main(){
scanf("%s",s+1);
n=strlen(s+1);
build(1,n,1);
scanf("%d",&m);
while(m--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",ask(l,r,1,n,1).cnt*2);
}
return 0;
}