CF 380C - Sereja and Brackets(线段树)

来源:互联网 发布:java 分库分表框架 编辑:程序博客网 时间:2024/05/08 13:08

题意:给出一个括号序列,有m个查询,每次查询区间[l,r]内正确的括号序列的长度的和。

思路:这题居然是线段树,没看出来啊……看了题解顿悟,感觉括号序列有很多神奇的性质。。。。

线段树的每个结点存三个数:sum是该区间的正确的括号序列的长度,lf是左括号的数量,rn是右括号的数量,那么将左右两个区间合并的时候,sum的值就是左右区间的sum的和在加上新匹配成功的括号长度,也就是左区间的左括号的数量和右区间的右括号的数量的较小值。


代码:


#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<map>#include<queue>#include<set>#include<stack>#include<cmath>#include<vector>#define inf 0x3f3f3f3f#define Inf 0x3FFFFFFFFFFFFFFFLL#define eps 1e-9#define pi acos(-1.0)using namespace std;typedef long long ll;const int maxn=1000000+10;int sum[maxn<<2],lf[maxn<<2],rn[maxn<<2];char str[maxn];void PushUp(int rt){    int tmp=min(lf[rt<<1],rn[rt<<1|1]);    sum[rt]=sum[rt<<1]+sum[rt<<1|1]+tmp*2;    lf[rt]=lf[rt<<1]+lf[rt<<1|1]-tmp;    rn[rt]=rn[rt<<1]+rn[rt<<1|1]-tmp;}void build(int l,int r,int rt){    if(l==r)    {        lf[rt]=rn[rt]=sum[rt]=0;        if(str[l-1]=='(') lf[rt]=1;        else rn[rt]=1;        return ;    }    int m=(l+r)>>1;    build(l,m,rt<<1);    build(m+1,r,rt<<1|1);    PushUp(rt);}int Query(int L,int R,int l,int r,int rt,int &lfs,int &rns){    if(l>=L&&r<=R)    {        lfs=lf[rt];        rns=rn[rt];        return sum[rt];    }    int m=(l+r)>>1;    if(m>=R) return Query(L,R,l,m,rt<<1,lfs,rns);    else if(m<L) return Query(L,R,m+1,r,rt<<1|1,lfs,rns);    else    {        int sum1,sum2,lf2,rn2,tmp;        sum1=Query(L,R,l,m,rt<<1,lfs,rns);        sum2=Query(L,R,m+1,r,rt<<1|1,lf2,rn2);        tmp=min(lfs,rn2);        lfs=lfs+lf2-tmp;        rns=rns+rn2-tmp;        return sum1+sum2+tmp*2;    }}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n;    scanf("%s",str);    n=strlen(str);    build(1,n,1);    int m,l,r,ltmp,rtmp;    scanf("%d",&m);    while(m--)    {        scanf("%d%d",&l,&r);        int ans=Query(l,r,1,n,1,ltmp,rtmp);        printf("%d\n",ans);    }    return 0;}

0 0
原创粉丝点击