[BZOJ1095]Hide 捉迷藏--括号序列&&线段树
2017-09-27 22:11
357 查看
岛姐 orz
看题解看了接近两个小时才想通这是在干什么经常看着某一部分就忘了上面一部分要干什么了,然后一脸蒙…
Emmmmm好在最后还是理解到了,十分巧妙
有点晚了,题解有时间再写吧,先贴几个挺不错的题解,一起看可能比较容易理解
—>岛姐的题解
–>博客园-沐阳
UPD at 2018.1.10 me的动态点分治做法传送门
自带大常数的代码
/************************************************************** Problem: 1095 User: Izumihanako Language: C++ Result: Accepted Time:2212 ms Memory:28280 kb ****************************************************************/ /*----------------------------------------- 岛姐orz 这种解法比较神奇 把树上的信息转换成了序列信息 然后对序列进行花式维护 整个题的重点在于线段树的updata函数 通过多维护几个东西,来快速的计算出答案 -----------------------------------------*/ #include <cstdio> #include <cstring> #include <algorithm> using namespace std ; int N , Q , head[100005] , tp ; int pos[100005] , cate[300005] , tot , dark[100005] ; struct Path{ int pre , to ; }p[200005] ; struct Node{ int dis , RP , RM , LP , LM , a , b ; //RP = right_plus , RM = right_minus //LP = left_plus , LM = left_minus Node *ls , *rs ; void set( int x ){ /*a代表的是']' 开口向右的那种括号 b代表的是'[' 开口向左的那种括号 因为把可以匹配的括号消除之后,剩下的一定是这样的: .....]]]]]][[[[[..... (a,b)二元组即可表示这个括号 */ /*如果为白点或者括号,就全部赋值为负无限大 这样保证了,凡是有括号是跨过了白点的,通通都取不到 */ a = ( x == -2 ) ; b = ( x == -1 ) ; dis = -0x3f3f3f3f ; if( x >= 1 && dark[x] ){ //如果没有关灯,就设为0,相对于负无穷,这就代表开始了 RP = RM = LP = LM = 0 ; } else RP = RM = LP = LM = -0x3f3f3f3f ; } void updata(){ if( rs->a > ls->b ){ a = ls->a + rs->a - ls->b ; b = rs->b ; } else { a = ls->a ; b = ls->b - rs->a + rs->b ; } //因为是左右拼接,所以是ls->Rx + rs->Lx才能拼接起中间部分 dis = max( ls->dis , rs->dis ) ; dis = max( dis , ls->RM + rs->LP ) ; dis = max( dis , ls->RP + rs->LM ) ; //因为RP必须与右端联通,所以需要直接 - rs->a + rs->b ,下面同理 RP = max( ls->RP - rs->a + rs->b , ls->RM + rs->a + rs->b ) ; RP = max( RP , rs->RP ) ; RM = max( ls->RM + rs->a - rs->b , rs->RM ) ; //LM维护的是b-a,因此和RM不太一样,是反过来的 LP = max( rs->LP + ls->a - ls->b , rs->LM + ls->a + ls->b ) ; LP = max( LP , ls->LP ) ; LM = max( rs->LM + ls->b - ls->a , ls->LM ) ; } }w[600005] , *root , *tw = w ; void In( int t1 , int t2 ){ p[++tp].pre = head[t1] ; p[ head[t1] = tp ].to = t2 ; } void dfs( int u , int f ){ /*进入的时候为'[' 在这里把点也直接放进序列,更方便处理 (就可以很方便的把白点设置成-inf从而阻断跨过白点的序列) */ cate[++tot] = -1 ; pos[ cate[++tot] = u ] = tot ; for( int i = head[u] ; i ; i = p[i].pre ){ int v = p[i].to ; if( v != f ) dfs( v , u ) ; } //出去的时候为']' cate[++tot] = -2 ; } Node *build( int lf , int rg ){ //线段树的日常--build Node *nd = ++tw ; if( lf == rg ) nd->set( cate[lf] ) ; else { int mid = ( lf + rg ) >> 1 ; nd->ls = build( lf , mid ) ; nd->rs = build( mid+1 , rg ) ; nd->updata() ; } return nd ; } void Modify( Node *nd , int lf , int rg , int pos ){ //线段树的日常--modify if( lf == rg ){ nd->set( cate[lf] ) ; return ; } int mid = ( lf + rg ) >> 1 ; if( pos <= mid ) Modify( nd->ls , lf , mid , pos ) ; else Modify( nd->rs , mid+1 , rg , pos ) ; nd->updata() ; } void solve(){ char ss[5] ; scanf( "%d" , &Q ) ; for( int i = 1 , x ; i <= Q ; i ++ ){ scanf( "%s" , ss ) ; switch( ss[0] ){ case 'G':{ //答案会在不断地updata后被统计到根节点 //因此每次询问直接输出根节点的dis即可 printf( "%d\n" , root->dis ) ; break; } case 'C':{ scanf( "%d" , &x ) ; //注意这里需要把开关灯状态更新 dark[x] ^= 1 ; Modify( root , 1 , tot , pos[x] ) ; break; } } } } //读入优化 等于scanf int read_(){ int rt = 0; char ch = getchar() ; while( ch < '0' || ch > '9' ) ch = getchar() ; while( ch >='0' && ch <='9' ) rt = (rt<<3) + (rt<<1) + ch - '0' , ch = getchar() ; return rt; } int main(){ scanf( "%d" , &N ) ; //一开始灯泡全部处于关闭状态,注意需要将标记打好 for( register int i = 1 ; i <= N ; i ++ ) dark[i] = 1 ; //日常建边&&一系列预备操作 for( register int i = 1 , t1 , t2 ; i < N ; i ++ ){ t1 = read_() ; t2 = read_(); In( t1 , t2 ) ; In( t2 , t1 ) ; } dfs( 1 , 1 ) ; root = build( 1 , tot ) ; solve() ; }
相关文章推荐
- bzoj1095 Hide 捉迷藏 括号序列&线段树
- BZOJ 1095: [ZJOI2007]Hide 捉迷藏(线段树维护括号序列)
- 【BZOJ】1095: [ZJOI2007]Hide 捉迷藏 括号序列+线段树
- bzoj 1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树)
- bzoj1095: [ZJOI2007]Hide 捉迷藏 线段树维护括号序列 点分治 链分治
- 【BZOJ1095】【ZJOI2007】Hide 捉迷藏 线段树维护括号序列 数据结构的压缩。
- BZOJ1095:Hide 捉迷藏 && SPOJ Qtree IV (树的三分治/括号序列)
- 【BZOJ 1095】 1095: [ZJOI2007]Hide 捉迷藏 (括号序列+线段树)
- bzoj1095 [ZJOI2007]Hide 捉迷藏 括号序列/动态点分治/树的数据生成
- 【BZOJ 1095】 [ZJOI2007]Hide 捉迷藏 括号序列
- [bzoj1095][ZJOI2007]Hide 捉迷藏——线段树+括号序列
- bzoj1095 [ZJOI2007]Hide 捉迷藏(动态点分治|括号序列)
- 【BZOJ1095】【ZJOI2007】捉迷藏 括号序列+线段树维护
- bzoj1095 [ZJOI2007]Hide 捉迷藏(括号序列+线段树/动态点分治+堆)
- 【线段树】【括号序列】【ZJOI2007】捉迷藏 Hide
- bzoj1095 线段树括号序列
- 括号序列 || 动态树分治 bzoj1095【ZJOI2007】Hide 捉迷藏
- [BZOJ1095][ZJOI2007][线段树]Hide捉迷藏
- BZOJ-1095 Hide 捉迷藏 模型建立+线段树
- BZOJ 1095 [ZJOI2007]Hide 捉迷藏