bzoj 1095 括号序列求两点距离
大致题意: 给一棵树,每个节点最开始都是黑色,有两种操作,1.询问树中相距最远的一对黑点的距离 2.反转一个节点的颜色
一种做法:
建立出树的括号序列,类似这样: [A[B][C]],所以长度为3*n
假如我们要询问AC间的距离,提取出中间的括号:[]],匹配消去后得到],其长度就是距离.
现在我们要做的就是修改点的状态,并且动态维护答案.要用到一些求与绝对值相关的式子的技巧.
1 /************************************************************** 2 Problem: 1095 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:2176 ms 7 Memory:55548 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #define min(a,b) ((a)<(b)?(a):(b)) 12 #define max(a,b) ((a)>(b)?(a):(b)) 13 #define N 100010 14 #define M N<<1 15 #define oo 0x3f3f3f3f 16 #define fprintf(...) 17 18 struct Node { 19 int v[7], c, e, a; 20 int lf, rg; 21 Node *ls, *rs; 22 void init( int type ) { 23 if( type==0 ) { 24 a = 0; 25 e = false; 26 c = 1; 27 for( int t=0; t<7; t++ ) v[t]=0; 28 } else if( type==-1 ) { // (1,0) 29 a = -1; 30 e = true; 31 c = 0; 32 v[1] = v[3] = v[6] = v[2] = v[5] = 1; 33 v[0] = v[4] = -1; 34 } else { // (0,1) 35 a = -1; 36 e = true; 37 c = 0; 38 v[1] = v[3] = v[6] = v[0] = v[4] = 1; 39 v[2] = v[5] = -1; 40 } 41 } 42 void update() { 43 e = ls->e && rs->e; 44 v[5] = ls->v[5] + rs->v[5]; 45 v[4] = ls->v[4] + rs->v[4]; 46 v[6] = max( ls->v[6]+rs->v[4], ls->v[5]+rs->v[6] ); 47 if( !ls->e && !rs->e ) { 48 v[0] = max( ls->v[0], ls->v[4]+rs->v[0] ); 49 v[1] = max( ls->v[1], max( ls->v[6]+rs->v[0], ls->v[5]+rs->v[1] ) ); 50 v[2] = max( rs->v[2], ls->v[2]+rs->v[5] ); 51 v[3] = max( rs->v[3], max( ls->v[3]+rs->v[4], ls->v[2]+rs->v[6] ) ); 52 a = max( max(ls->v[3]+rs->v[0],ls->v[2]+rs->v[1]), max(ls->a,rs->a) ); 53 } else if( !ls->e ) { 54 v[0] = ls->v[0]; 55 v[1] = ls->v[1]; 56 v[2] = ls->v[2]+rs->v[5]; 57 v[3] = max( ls->v[3]+rs->v[4], ls->v[2]+rs->v[6] ); 58 a = ls->a; 59 } else if( !rs->e ) { 60 v[0] = ls->v[4]+rs->v[0]; 61 v[1] = max( ls->v[6]+rs->v[0], ls->v[5]+rs->v[1] ); 62 v[2] = rs->v[2]; 63 v[3] = rs->v[3]; 64 a = rs->a; 65 } else { 66 a = -1; 67 } 68 } 69 void reverse( int pos ) { 70 if( lf==rg ) { 71 if( c ) { 72 c = 0; 73 a = -1; 74 e = true; 75 } else { 76 c = 1; 77 a = 0; 78 e = false; 79 } 80 return; 81 } 82 int mid=(lf+rg)>>1; 83 if( pos<=mid ) ls->reverse(pos); 84 else rs->reverse(pos); 85 update(); 86 } 87 }pool[N*3*3], *tail=pool, *root; 88 89 int n, m; 90 int head[N], dest[M], next[M], etot; 91 int dfn[N], sgn[N*3], fat[N], idc; 92 93 void adde( int u, int v ) { 94 etot++; 95 next[etot] = head[u]; 96 dest[etot] = v; 97 head[u] = etot; 98 } 99 void dfs( int u ) { 100 sgn[++idc] = 1; 101 dfn[u] = ++idc; 102 fprintf( stderr, "[" ); 103 fprintf( stderr, "%d", u ); 104 for( int t=head[u]; t; t=next[t] ) { 105 int v=dest[t]; 106 if( v==fat[u] ) continue; 107 fat[v] = u; 108 dfs(v); 109 } 110 sgn[++idc] = -1; 111 fprintf( stderr, "]" ); 112 } 113 Node *build( int lf, int rg ) { 114 Node *nd = ++tail; 115 nd->lf=lf, nd->rg=rg; 116 if( lf==rg ) { 117 nd->init( sgn[lf] ); 118 } else { 119 int mid=(lf+rg)>>1; 120 nd->ls = build( lf, mid ); 121 nd->rs = build( mid+1, rg ); 122 nd->update(); 123 } 124 fprintf( stderr, "[%d,%d] a=%2d e=%d v[0~6] = %2d %2d %2d %2d %2d %2d %2d\n", 125 lf, rg, nd->a, nd->e, nd->v[0], nd->v[1], 126 nd->v[2], nd->v[3], nd->v[4], nd->v[5], nd->v[6] ); 127 return nd; 128 } 129 int main() { 130 scanf( "%d", &n ); 131 for( int i=1,u,v; i<n; i++ ) { 132 scanf( "%d%d", &u, &v ); 133 adde( u, v ); 134 adde( v, u ); 135 } 136 for( int i=1; i<=n+n+n; i++ ) 137 fprintf( stderr, "%d", i%10 ); 138 fprintf( stderr, "\n" ); 139 fat[1] = 0; 140 dfs(1); 141 fprintf( stderr, "\n" ); 142 root = build( 1, idc ); 143 scanf( "%d", &m ); 144 for( int i=1,u; i<=m; i++ ) { 145 char ch[10]; 146 scanf( "%s\n", ch ); 147 if( ch[0]=='G' ) { 148 printf( "%d\n", root->a ); 149 } else { 150 scanf( "%d", &u ); 151 root->reverse(dfn[u]); 152 } 153 } 154 }
另一种做法大概是用点分,然后用堆维护最值.