CF308C-Sereja and Brackets-(线段树+括号匹配)
题意:给出一段括号,多次询问某个区间内能匹配多少括号。
题解:线段树,结构体三个属性,多余的左括号l,多余的右括号r,能够匹配的括号数val。
当前结点的val=左儿子的val+右儿子的val+min(左儿子的l,右儿子的r)。原本匹配好的括号数加上多余的可以匹配的括号。
同时在左右儿子的l和r累加后减去新匹配的括号数。
#include<stdio.h> #include<iostream> #include<algorithm> #include<cstring> #include<math.h> #include<string> #include<map> #include<queue> #include<stack> #include<set> #define ll long long #define inf 0x3f3f3f3f using namespace std; const double PI=acos(-1); struct node { int l; int r; int val; }; node sum[1000086*4]; char s[1000086]; int n,m,L,R; void build(int l,int r,int rt) { if(l==r)///底层的只有一个括号,不需要管val { if(s[l]=='(') sum[rt].l++; else sum[rt].r++; return; } int mid=(l+r)/2; build(l,mid,rt*2); build(mid+1,r,rt*2+1); int minn=min( sum[rt*2].l,sum[rt*2+1].r ); sum[rt].val=sum[rt*2].val+sum[rt*2+1].val+minn; sum[rt].l=sum[rt*2].l+sum[rt*2+1].l-minn; sum[rt].r=sum[rt*2].r+sum[rt*2+1].r-minn; } node query(int l,int r,int rt) { if( L<=l && r<=R ) return sum[rt]; int mid=(l+r)/2; node ans1={0,0,0},ans2={0,0,0};///必须要定义值,否则如果有一个if语句进不去,相加过程出错 if( L<=mid ) ans1=query(l,mid,rt*2); if( R>mid ) ans2=query(mid+1,r,rt*2+1); int minn2=min(ans1.l,ans2.r); return { ans1.l+ans2.l-minn2, ans1.r+ans2.r-minn2, ans1.val+ans2.val+minn2 }; } int main()///CF380C { while(scanf("%s",s+1)!=EOF) { memset(sum,0,sizeof(sum)); n=strlen(s+1); scanf("%d",&m); build(1,n,1); while(m--) { scanf("%d%d",&L,&R); printf("%d\n",query(1,n,1).val*2); } } return 0; }