吾好梦中做题------线段树状压

原题
这题的一开始的思路就是将左右括号给化成-1与1的形式,因为它只支持这样的合法括号:
1.()是合法括号序列;
2.如果A是合法的,那么(A)也是合法的;
3.如果A和B都合法,那么AB合法。
所以便可以想出将‘(’为1,’)'为-1,那么就相当于是在求前缀合之间的关系(这个关系并不复杂,就是以pos为左端点,到最远的右端点,使前缀和为0,且,这个区间的前缀和中不可以包含-1),我们可以用线段树维护前缀和。
楼主一开始使用了二分,但是超时了。后来换了一种新思路。

旧思路(二分超时):
比如询问的是pos到n。我们首先可以求出pos-1的前缀合为las。然后再从pos到n的前缀和中求最小值fut。(如果s[pos]=’)’,直接输出0即可)
1:如果fut>las,不存在,输出0
2:如果fut=las,存在0,求出最靠右边的,前缀和为0的位置。它就是答案。
3:如果fut<las,存在-1,求从左向右数第一个-1的位置,它的左边的位置就是答案。

新思路:

一开始的超时代码:

#include<bits/stdc++.h>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int MX=5e5+9;
int T,n,m,pos,order,t[MX<<2],laze[MX<<2],a[MX],sum[MX];
char s[MX];
 
void build(int k,int l,int r){
    laze[k]=0;
    if( l==r ){
        t[k]=sum[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    t[k]=min(t[k<<1],t[k<<1|1]);
}
 
void pushdown(int k){
    if( laze[k] ){
        laze[k<<1]+=laze[k];
        laze[k<<1|1]+=laze[k];
        t[k<<1]+=laze[k];
        t[k<<1|1]+=laze[k];
        laze[k]=0;
    }
}
 
void update(int k,int l,int r,int L,int val){
    if( L<=l ){
        t[k]+=val;
        laze[k]+=val;
        return ;
    }
    pushdown(k);
    int mid=(l+r)>>1;
    if( L<=mid )
        update(lson,L,val);
    update(rson,L,val);
    t[k]=min(t[k<<1],t[k<<1|1]);
}
 
int que(int k,int l,int r,int L,int R){
    if( !L )
        return 0;
    if( L<=l && r<=R )
        return t[k];
    pushdown(k);
    int mid=(l+r)>>1,ans=MX;
    if( L<=mid )
        ans=min(ans,que(lson,L,R));
    if( mid<R )
        ans=min(ans,que(rson,L,R));
    return ans;
}
 
int main()
{
   // freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while( T-- ){
        scanf("%d %d",&n,&m);
        scanf("%s",s+1);
        for( int i=1 ; i<=n ; i++ )
            a[i]=s[i]=='('?1:-1;
        for( int i=1 ; i<=n ; i++ )
            sum[i]=sum[i-1]+a[i];
        build(1,1,n);
        while( m-- ){
            scanf("%d %d",&order,&pos);
            if( order==1 ){
                s[pos]=s[pos]==')'?'(':')';
                update(1,1,n,pos,s[pos]=='('?2:-2);
            }
            else{
                if( s[pos]==')' )
                    printf("0\n");
                else{
                    int las=que(1,1,n,pos-1,pos-1);
                    int ans,fut=que(1,1,n,pos,n);
                    if( las==fut ){
                        int l=pos,r=n;
                        while( l<=r ){
                            int mid=(l+r)>>1;
                            if( las==que(1,1,n,mid,r) ){
                                l=mid+1;
                                ans=mid-pos;
                            }
                            else
                                r=mid-1;
                        }
                        printf("%d\n",ans);
                    }
                    else if( las>fut ){
                        int l=pos,r=n;
                        while( l<=r ){
                            int mid=(l+r)>>1;
                            if( las>que(1,1,n,l,mid) ){
                                r=mid-1;
                                ans=mid-pos;
                            }
                            else
                                l=mid+1;
                        }
                        printf("%d\n",ans);
                    }
                    else
                        printf("0\n");
                }
            }
        }
    }
    return 0;
}

新思路:

#include<bits/stdc++.h>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int MX=5e5+9;
int T,n,m,order,x,t[MX<<2],laze[MX<<2],a[MX];
char s[MX];
void pushdown(int k){
    if( laze[k] ){
        laze[k<<1]+=laze[k];
        laze[k<<1|1]+=laze[k];
        t[k<<1]+=laze[k];
        t[k<<1|1]+=laze[k];
        laze[k]=0;
    }
}

void build(int k,int l,int r){
    laze[k]=0;
    if( l==r ){
        t[k]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson);
    build(rson);
    t[k]=min(t[k<<1],t[k<<1|1]);
}

void update(int k,int l,int r,int L,int val){
    if( L<=l ){
        t[k]+=val;
        laze[k]+=val;
        return ;
    }
    pushdown(k);
    int mid=(l+r)>>1;
    if( L<=mid )
        update(lson,L,val);
    update(rson,L,val);
    t[k]=min(t[k<<1],t[k<<1|1]);
}

int que(int k,int l,int r,int L,int R){
    if( L<=l && r<=R )
        return t[k];
    pushdown(k);
    int mid=(l+r)>>1,ans=MX;
    if( L<=mid )
        ans=min(ans,que(lson,L,R));
    if( mid<R )
        ans=min(ans,que(rson,L,R));
    return ans;
}

int que1(int k,int l,int r,int L,int R,int val){
    if( l==r && t[k]==val )
        return l;
    pushdown(k);
    int mid=(l+r)>>1;
    if( L<=mid && t[k<<1]<=val ){
        int ans=que1(lson,L,R,val);
        if( ans>0 )
            return ans;
    }
    if( mid<R && t[k<<1|1]<=val ){
        int ans=que1(rson,L,R,val);
        if( ans>0 )
            return ans;
    }
    return -1;
}

int que2(int k,int l,int r,int L,int R,int val){
    if( l==r && t[k]==val )
        return l;
    pushdown(k);
    int mid=(l+r)>>1;
    if( mid<R && t[k<<1|1]<=val ){
        int ans=que2(rson,L,R,val);
        if( ans>0 )
            return ans;
    }
    if( L<=mid && t[k<<1]<=val ){
        int ans=que2(lson,L,R,val);
        if( ans>0 )
            return ans;
    }
    return -1;
}

int main()
{
 //   freopen("input.txt","r",stdin);
    scanf("%d",&T);
    while( T-- ){
        scanf("%d %d",&n,&m);
        scanf("%s",s+1);
        for( int i=1 ; i<=n ; i++ )
            a[i]=a[i-1]+(s[i]=='('?1:-1);
        build(1,1,n);
        while( m-- ){
            scanf("%d %d",&order,&x);
            if( order==1 ){
                s[x]=s[x]=='('?')':'(';
                update(1,1,n,x,s[x]=='('?2:-2);
            }
            else{
                if( s[x]==')' )
                    printf("0\n");
                else{
                    int zuo=(x==1?0:que(1,1,n,x-1,x-1));   // 要小心x=0的时候,
                    int you=que(1,1,n,x,n);
                    if( zuo<you )
                        printf("0\n");   //当右边全部都是(时
                    else{
                        int pos=que1(1,1,n,x,n,zuo-1);   // 求出第一个‘-1’(此-1非彼-1)的位置
                        if( pos==-1 ) 
                            pos=n+1;
                        int ans=que2(1,1,n,x,pos-1,zuo);   // 在这个范围内求出最靠右的‘0’的位置
                        printf("%d\n",ans-x+1); 
                    }
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值