UESTC 1546 Bracket Sequence

本文介绍了一种基于线段树的数据结构实现,用于高效处理括号序列的更新与查询操作,包括设置区间内的括号类型及翻转区间内括号方向,并判断给定区间是否构成合法的括号序列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


线段树,把左右括号标记成-1,1。。。合法的区间的总和为零,且从左向右的累加和 小于等于 0
维护每个结点的sum max,为方便reserv再多维护一个min reserv时交换max,min的绝对值再成-1
set与reserv并存时,要先reserv再set

Time Limit: 3000MS Memory Limit: 65536KB 64bit IO Format: %lld & %llu

[]   [Go Back]   [Status]  

Description

There is a sequence of brackets, which supports two kinds of operations.
1. we can choose a interval [l,r], and set all the elements range in this interval to left bracket or right bracket. 
2. we can reverse a interval, which means that for all the elements range in [l,r], if it's left bracket at that time, we change it into right bracket, vice versa.
Fish is fond of "Regular Bracket Sequence", so he want to know whether a interval [l,r] of the sequence is regular or not after doing some opearations.

Let us define a regular brackets sequence in the following way: 

1. Empty sequence is a regular sequence. 
2. If S is a regular sequence, then (S) is also a regular sequences. 
3. If A and B are regular sequences, then AB is a regular sequence.

Input

In the first line there is an integer T (T≤10), indicates the number of test cases. Each case begins with a line containing an integers N (N ≤ 100,000 and N is a even number), the size of the initial brackets sequence. The next line contains a string whose length is N consisting of '(' and ')'. In the third of each test case, there is an integer M(M ≤ 100,000) indicates the number of queries. Each of the following M lines contains one operation as mentioned below. The index of the bracket sequence is labeled from 0 to N - 1.

Three operation description:
set l r c: change all the elements range in [l,r] into '(' or ')'.(c is '(' or ')')
reverse l r: reverse the interval [l,r]
query l,r: you should answer that interval [l,r] is regular or not

Output

For each test case, print a line containing the test case number (beginning with 1) on its own line, then the answer for each "query" operation, if the interval is regular, print "YES", otherwise print "NO", one on each line.
Print a blank line after each test case.

Sample Input

1
6
((()))
8
query 0 5
set 0 5 (
query 0 5
reverse 3 5
query 0 5
query 1 4
query 2 3
query 0 4

Sample Output

Case 1:
YES
NO
YES
YES
YES
NO

Hint

Huge input, use "scanf" instead of "cin".

Source

Classic Problem

#include <iostream>
#include <cstring>
#include <cstdio>

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

using namespace std;

const int maxn=111111;

int setv[maxn<<2],rev[maxn<<2],sum[maxn<<2],mx[maxn<<2],mi[maxn<<2];
char str[maxn];

void reserve(int rt)
{
    sum[rt]=-sum[rt];
    swap(mx[rt],mi[rt]);
    mx[rt]=-mx[rt];
    mi[rt]=-mi[rt];
    rev[rt]^=1;
}

void set(int op,int rt,int len)
{
    sum[rt]=op*len;
    mx[rt]=sum[rt]>0?sum[rt]:0;
    mi[rt]=sum[rt]<0?sum[rt]:0;
    setv[rt]=op;rev[rt]=0;
}

void push_down(int rt,int ll,int lr)
{
    if(rev[rt])
    {
        if(setv[rt]) setv[rt]*=-1;
        else reserve(rt<<1),reserve(rt<<1|1);
        rev[rt]=0;
    }
    if(setv[rt])
    {
        set(setv[rt],rt<<1,ll),set(setv[rt],rt<<1|1,lr);
        setv[rt]=0;
    }
}

void push_up(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    mx[rt]=max(mx[rt<<1],sum[rt<<1]+mx[rt<<1|1]);
    mi[rt]=min(mi[rt<<1],sum[rt<<1]+mi[rt<<1|1]);
}

void build(int l,int r,int rt)
{
    setv[rt]=rev[rt]=0;
    if(l==r)
    {
        sum[rt]=(str[l]=='(')?-1:1;
        mx[rt]=(sum[rt]<0)?0:1;
        mi[rt]=(sum[rt]<0)?-1:0;
        return;
    }
    int m=(l+r)>>1;
    build(lson),build(rson);
    push_up(rt);
}

void update(int L,int R,int c,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        if(c) set(c,rt,r-l+1);
        else reserve(rt);
        return ;
    }
    int m=(l+r)>>1;
    push_down(rt,m-l+1,r-m);
    if(L<=m) update(L,R,c,lson);
    if(R>m) update(L,R,c,rson);
    push_up(rt);
}

int query_sum(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return sum[rt];
    }
    int m=(l+r)>>1,ans=0;
    push_down(rt,m-l+1,r-m);
    if(L<=m) ans+=query_sum(L,R,lson);
    if(R>m) ans+=query_sum(L,R,rson);
    push_up(rt);
    return ans;
}

int query_max(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
    {
        return mx[rt];
    }
    int m=(l+r)>>1,ret;
    push_down(rt,m-l+1,r-m);
    if(R<=m) ret=query_max(L,R,lson);
    else if(L>m) ret=query_max(L,R,rson);
    else ret=max(query_max(L,R,lson),query_sum(L,R,lson)+query_max(L,R,rson));
    push_up(rt);
    return ret;
}

int main()
{
    int t,cas=1;
    char cmd[20];
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        printf("Case %d:\n",cas++);
        scanf("%d",&n);
        scanf("%s",str);
        build(0,n-1,1);
        scanf("%d",&m);
        while(m--)
        {
            scanf("%s",cmd);
            if(cmd[0]=='s')
            {
                int a,b; char c[10];
                scanf("%d%d%s",&a,&b,c);
                if(c[0]=='(')
                    update(a,b,-1,0,n-1,1);
                else if(c[0]==')')
                    update(a,b,1,0,n-1,1);
            }
            else if(cmd[0]=='r')
            {
                int a,b;
                scanf("%d%d",&a,&b);
                update(a,b,0,0,n-1,1);
            }
            else if(cmd[0]=='q')
            {
                int a,b;
                scanf("%d%d",&a,&b);
                if(!query_sum(a,b,0,n-1,1)&&!query_max(a,b,0,n-1,1)) puts("YES");
                else puts("NO");
            }
        }
        putchar(10);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值