[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() ;
}
發佈了268 篇原創文章 · 獲贊 29 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章