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;
}
CF308C

 

posted @ 2019-08-08 18:55  守林鸟  阅读(281)  评论(0编辑  收藏  举报