传送门:【HDU】4987 Little Devil I
题目分析:树链剖分可以写诶!
首先毋庸置疑,树链剖分先~
接下来我们给线段树两个标记flip以及mark。
flip:该树上路径被翻转的情况,用布尔值表示。
mark:该路径周围的路径被翻转的情况,用布尔值表示。
定义查询的时候,对于一个条轻边,我们看他自己被翻转的次数以及深度较浅的端点(父亲)标记的次数,相加为奇数则该边为黑边。
每次我们进行操作一时,直接更新所有路径上的边即可。
进行操作二时,标记路径上所有点,因为一条边看的是自己翻转次数以及父亲节点翻转次数,所以这条路径上的轻边是在这次操作中不应该翻转的,我们就应该把这条边直接翻转来抵消父亲节点上mark标记的改变对他的影响。而对于mark标记影响的重边我们直接翻转!这样在以后查询的时候,如果是一条重链区间我们就可以很轻松的返回结果。还有就是如果这条路径的最高点上方还有一条边,直接翻转那条边。
操作三,也就是查询,对于一条重链,我们直接返回sum即可,重点是轻边,由于我们上面的操作,轻边的黑白是与本身的翻转次数以及父亲的标记次数有关的,我们拉出来特别处理。其他的就没什么了。
昨天晚上+今天早上想这道题老是会睡着。。。。真是不容易。。。
代码如下:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std ; typedef long long LL ; #define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next ) #define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i ) #define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i ) #define FOR( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i ) #define clr( a , x ) memset ( a , x , sizeof a ) #define cpy( a , x ) memcpy ( a , x , sizeof a ) #define ls ( o << 1 ) #define rs ( o << 1 | 1 ) #define lson ls , l , m #define rson rs , m + 1 , r #define rt o , l , r #define root 1 , 1 , n #define mid ( ( l + r ) >> 1 ) const int MAXN = 100005 ; const int MAXE = 200005 ; struct Edge { int v ; Edge* next ; } E[MAXE] , *H[MAXN] , *edge ; bool mark[MAXN << 2] ; bool flip[MAXN << 2] ; int sum[MAXN << 2] ; int siz[MAXN] ; int pos[MAXN] ; int pre[MAXN] ; int top[MAXN] ; int dep[MAXN] ; int son[MAXN] ; int val[MAXN] ; int tree_idx ; int n , q ; void clear () { clr ( mark , 0 ) ; clr ( flip , 0 ) ; clr ( sum , 0 ) ; clr ( H , 0 ) ; tree_idx = 0 ; siz[0] = 0 ; dep[0] = 0 ; edge = E ; } void addedge ( int u , int v ) { edge -> v = v ; edge -> next = H[u] ; H[u] = edge ++ ; } void dfs ( int u ) { siz[u] = 1 ; son[u] = 0 ; travel ( e , H , u ) { int v = e -> v ; if ( v != pre[u] ) { pre[v] = u ; dep[v] = dep[u] + 1 ; dfs ( v ) ; siz[u] += siz[v] ; if ( siz[v] > siz[son[u]] ) son[u] = v ; } } } void rewrite ( int u , int top_element ) { top[u] = top_element ; pos[u] = ++ tree_idx ; if ( son[u] ) rewrite ( son[u] , top_element ) ; travel ( e , H , u ) { int v = e -> v ; if ( v != son[u] && v != pre[u] ) { rewrite ( v , v ) ; } } } void pushup ( int o ) { sum[o] = sum[ls] + sum[rs] ; } void pushdown ( int o , int l , int r ) { if ( flip[o] ) { int m = mid ; flip[ls] ^= 1 ; flip[rs] ^= 1 ; sum[ls] = m - l + 1 - sum[ls] ; sum[rs] = r - m - sum[rs] ; flip[o] = 0 ; } if ( mark[o] ) { mark[ls] ^= 1 ; mark[rs] ^= 1 ; mark[o] = 0 ; } } void Flip ( int L , int R , int o , int l , int r ) { if ( L <= l && r <= R ) { flip[o] ^= 1 ; sum[o] = r - l + 1 - sum[o] ; return ; } int m = mid ; pushdown ( rt ) ; if ( L <= m ) Flip ( L , R , lson ) ; if ( m < R ) Flip ( L , R , rson ) ; pushup ( o ) ; } void Mark ( int L , int R , int o , int l , int r ) { if ( L <= l && r <= R ) { mark[o] ^= 1 ; return ; } int m = mid ; pushdown ( rt ) ; if ( L <= m ) Mark ( L , R , lson ) ; if ( m < R ) Mark ( L , R , rson ) ; pushup ( o ) ; } int query ( int L , int R , int o , int l , int r ) { if ( L <= l && r <= R ) return sum[o] ; int m = mid ; pushdown ( rt ) ; if ( R <= m ) return query ( L , R , lson ) ; if ( m < L ) return query ( L , R , rson ) ; return query ( L , R , lson ) + query ( L , R , rson ) ; } bool Query_Mark_On_Parent ( int pos , int o , int l , int r ) { if ( l == r ) return mark[o] ; int m = mid ; pushdown ( rt ) ; if ( pos <= m ) return Query_Mark_On_Parent ( pos , lson ) ; else return Query_Mark_On_Parent ( pos , rson ) ; } void Reverse_Path ( int x , int y ) { while ( top[x] != top[y] ) { if ( dep[top[x]] < dep[top[y]] ) swap ( x , y ) ; Flip ( pos[top[x]] , pos[x] , root ) ; x = pre[top[x]] ; } if ( x == y ) return ; if ( dep[x] > dep[y] ) swap ( x , y ) ; Flip ( pos[x] + 1 , pos[y] , root ) ; } void Reverse_Adjacent_Path ( int x , int y ) { while ( top[x] != top[y] ) { if ( dep[top[x]] < dep[top[y]] ) swap ( x , y ) ; Mark ( pos[top[x]] , pos[x] , root ) ; //以下两条是为消去Mark的影响 if ( son[x] ) Flip ( pos[x] + 1 , pos[x] + 1 , root ) ; Flip ( pos[top[x]] , pos[top[x]] , root ) ; x = pre[top[x]] ; } if ( dep[x] > dep[y] ) swap ( x , y ) ; Mark ( pos[x] , pos[y] , root ) ; if ( pre[x] ) Flip ( pos[x] , pos[x] , root ) ;//Flip替代子节点mark的影响 if ( son[y] ) Flip ( pos[y] + 1 , pos[y] + 1 , root ) ;//Flip消除父节点mark的影响 } int Query_Sum ( int x , int y , int res = 0 ) { while ( top[x] != top[y] ) { if ( dep[top[x]] < dep[top[y]] ) swap ( x , y ) ; if ( top[x] != x ) res += query ( pos[top[x]] + 1 , pos[x] , root ) ; res += query ( pos[top[x]] , pos[top[x]] , root ) ^ Query_Mark_On_Parent ( pos[pre[top[x]]] , root ) ; x = pre[top[x]] ; } if ( x == y ) return res ; if ( dep[x] > dep[y] ) swap ( x , y ) ; res += query ( pos[x] + 1 , pos[y] , root ) ; return res ; } void solve () { int x , y , op ; clear () ; scanf ( "%d" , &n ) ; rep ( i , 1 , n ) { scanf ( "%d%d" , &x , &y ) ; addedge ( x , y ) ; addedge ( y , x ) ; } dfs ( 1 ) ; rewrite ( 1 , 1 ) ; scanf ( "%d" , &q ) ; while ( q -- ) { scanf ( "%d%d%d" , &op , &x , &y ) ; if ( op == 1 ) Reverse_Path ( x , y ) ; if ( op == 2 ) Reverse_Adjacent_Path ( x , y ) ; if ( op == 3 ) printf ( "%d\n" , Query_Sum ( x , y ) ) ; } } int main () { int T ; scanf ( "%d" , &T ) ; while ( T -- ) solve () ; return 0 ; }