说在前面
好久没码过…已经码不动了
题目
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() ;
}