好久没码过…已经码不动了
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() ; }