[BZOJ2329]/[BZOJ2209]-括号修复-Splay维护信息

说在前面

好久没码过…已经码不动了


题目

BZOJ2329传送门
BZOJ2209传送门
看题可戳传送门,2209是2329的简化版(虽然它们都是省选题)


解法

这个题的难点在于 取反操作 和 翻转操作 的维护
取反操作 和 翻转操作 并不能像普通信息一样直接打tag,因为是不可以直接翻转的,举个例子:
( ( ( ( ) ) 反转变成了 ) ) ) ) ( ( ,如果直接取反显然GG,翻转也类似

原因是,我们在统计贡献的时候,实际采取的策略是:「从左到右,靠左多余右括号不可抵消」。即 ( ( ) ) 这样是可以抵消的,而反转之后的 ) ) ( ( 不行。这导致我们不能直接 反/翻转

但是我们可以发现,反转后的策略,对于原序列的策略是:「从左到右,靠左多余左括号不可抵消」。也就是说,反转之后的答案应该这样维护:原序列如果是 ) ) ( ( 则可以抵消的而 ( ( ) ) 不行。(翻转类似,翻转=反转再交换儿子,所以翻转和反转的策略一样)

那么我们需要维护一些东西,使得在策略发生改变之后,仍然可以得出答案
那么显然的方法就是,两种策略都维护
所以我们只需维护,左边最多连续左括号/右括号,右边最多连续左括号/右括号 即可

注意 反转 和 翻转 以及 覆盖 时的标记细节
然后这题就做完了


下面是代码

me采用的是 左括号-1,右括号+1,统计 lmin/lmax,rmin/rmax 的方式
本质和上面是一样的
(调试语句没有删)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

int N , M ;
char s[100005] ;
struct Node{
    Node *ch[2] , *fa ;
    int cur , lmax , rmax , lmin , rmin , siz , tag , sum , id ;
    bool frev , finv ;
    Node( int x = 0 ): cur( x ) , sum( x ) {
        tag = 0 , siz = 1 ;
        frev = finv = false ;
        lmax = rmax = lmin = rmin = 0 ;
        if( x > 0 ) lmax = rmax = 1 ;
        if( x < 0 ) lmin = rmin = -1 ;
    } ;
    void update( ){
        siz = ch[0]->siz + 1 + ch[1]->siz ;
        sum = ch[0]->sum + cur + ch[1]->sum ;
        lmax = max( ch[0]->lmax , ch[0]->sum + cur + ch[1]->lmax ) ;
        lmin = min( ch[0]->lmin , ch[0]->sum + cur + ch[1]->lmin ) ;
        rmax = max( ch[1]->rmax , ch[0]->rmax + cur + ch[1]->sum ) ;
        rmin = min( ch[1]->rmin , ch[0]->rmin + cur + ch[1]->sum ) ;
    }
    void cover( int x ){
        cur = tag = x , sum = x * siz ;
        if( x > 0 ) lmax = rmax = sum , lmin = rmin = 0 ;
        else lmin = rmin = sum , lmax = rmax = 0 ;
        frev = finv = false ;
    }
    void inv(){
        swap( lmax , lmin ) , lmax = -lmax , lmin = -lmin ;
        swap( rmax , rmin ) , rmax = -rmax , rmin = -rmin ;
        cur = -cur , tag = -tag , sum = -sum ;
        finv ^= 1 ;
    }
    void rev(){
        swap( lmax , rmax ) , swap( lmin , rmin ) ;
        swap( ch[0] , ch[1] ) , frev ^= 1 ;
    }
    void pushdown(){
        if( ch[0]->fa != ch[0] ){
            if( frev ) ch[0]->rev() ;
            if( finv ) ch[0]->inv() ;
            if( tag ) ch[0]->cover( tag ) ;
        } if( ch[1]->fa != ch[1] ){
            if( frev ) ch[1]->rev() ;
            if( finv ) ch[1]->inv() ;
            if( tag ) ch[1]->cover( tag ) ;
        } frev = finv = false , tag = 0 ;
    }
} *root , *sta[100005] , *ans , *null ;

Node *build( int lf , int rg , Node *fa ){
    int mid = ( lf + rg ) >> 1 ;
    Node *nd = new Node( s[mid] ) ;
    nd->ch[0] = nd->ch[1] = null , nd->fa = fa ;
    if( lf < mid ) nd->ch[0] = build( lf , mid - 1 , nd ) ;
    if( mid < rg ) nd->ch[1] = build( mid + 1 , rg , nd ) ;
    nd->update() ; return nd ;
}

int d_c , speci ;
void dfs( Node *nd ){
    if( nd == null ) return ;
    nd->pushdown() ;
    dfs( nd->ch[0] ) ;
    nd->id = d_c ++ ;
    dfs( nd->ch[1] ) ;
}

void dfs_print( Node *nd ){
    if( nd == null ) return ;
    printf( "%d(%p) %d --- %d %d\n" , nd->id , nd , nd->fa==null?-1:nd->fa->id , nd->lmax , nd->rmin ) ;
    dfs_print( nd->ch[0] ) , dfs_print( nd->ch[1] ) ;
}

void Rotate( Node *nd , bool k ){
    Node *x = nd->ch[k] ;
    if( nd->fa != null ){
        if( nd->fa->ch[0] == nd ) nd->fa->ch[0] = x ;
        if( nd->fa->ch[1] == nd ) nd->fa->ch[1] = x ;
    } x->fa = nd->fa ;
    if( x->ch[k^1] != null ) x->ch[k^1]->fa = nd ;
    nd->ch[k] = x->ch[k^1] ;
    x->ch[k^1] = nd , nd->fa = x ;
    nd->update() , x->update() ;
}

void Splay( Node *nd , Node *aim ){
    Node *tmp = nd ; int tp = 0 ;
    while( tmp != null ) sta[++tp] = tmp , tmp = tmp->fa ;
    while( tp ) sta[tp]->pushdown() , tp -- ;

    while( nd->fa != aim ){
        Node *fa = nd->fa , *gdfa = fa->fa ;
        int pn = ( fa->ch[1] == nd ) , pf ;
        if( gdfa != aim ){
            pf = gdfa->ch[1] == fa ;
            if( pn == pf ) swap( gdfa , fa ) ;
            Rotate( fa , pn ) , Rotate( gdfa , pf ) ;
        } else Rotate( fa , pn ) ;
    } if( aim == null ) root = nd ;

    if( !speci ) return ;
    d_c = 0 , dfs( root ) , dfs_print( root ) ; puts( "spe end" ) ;
}

Node *Kth( Node *nd , int K ){
    nd->pushdown() ;
    int Lsiz = nd->ch[0]->siz ;
    if( K == Lsiz + 1 ) return nd ;
    if( K <= Lsiz ) return Kth( nd->ch[0] , K ) ;
    else return Kth( nd->ch[1] , K - Lsiz - 1 ) ;
}

void getInterval( int lf , int rg ){
    Node *LF = Kth( root , lf ) , *RG = Kth( root , rg + 2 ) ;
    Splay( LF , null ) , Splay( RG , LF ) ;
}

void solve(){
    char opt[15] , change[5] ;
    int illegal_opt = 0 ;
    for( int i = 1 , L , R ; i <= M ; i ++ ){
        scanf( "%s%d%d" , opt , &L , &R ) ;
        if( opt[0] == 'R' ) scanf( "%s" , change ) ;
        if( L > R ) { illegal_opt ++ ; continue ; }

        getInterval( L , R ) ;
        if( opt[0] == 'R' ) root->ch[1]->ch[0]->cover( change[0] == '(' ? -1 : 1 ) ;
        else if( opt[0] == 'S' ) root->ch[1]->ch[0]->rev() ;    
        else if( opt[0] == 'I' ) root->ch[1]->ch[0]->inv() ;
        else{
            ans = root->ch[1]->ch[0] ;
            if( ( R - L + 1 )&1 ){ puts( "-1" ) ; continue ; } 
            printf( "%d\n" , ( abs( ans->lmax ) + 1 ) / 2 + ( abs( ans->rmin ) + 1 ) / 2 ) ;
        }
        root->ch[1]->update() , root->update() ; 
        //d_c = 0 , dfs( root ) ; dfs_print( root ) ; puts( "" ) ;
    }
}

int main(){
    null = new Node( 0 ) ; null->siz = 0 ;
    null->ch[0] = null->ch[1] = null->fa = null ;

    scanf( "%d%d%s" , &N , &M , s + 1 ) ;
    for( int i = 1 ; i <= N ; i ++ )
        s[i] = ( s[i] == '(' ? -1 : 1 ) ;
    root = build( 0 , N + 1 , null ) ;
    solve() ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值