【HDU】4836 The Query on the Tree dfs+线段树

来源:互联网 发布:windows 不激活会怎样 编辑:程序博客网 时间:2024/05/16 07:05

传送门:【HDU】4836 The Query on the Tree


题目分析:首先如果不换根的话,就可以用dfs求时间戳+树状数组维护即可。


现在多了换根操作,我们该怎么处理?

首先因为换根并不会改变树的结构,所以我们依旧dfs出一棵树来。

对于修改,我们改变该点在树状数组上对应位置的值即可。

对于换根,我们直接将root置为要换的节点。

对于查询,如果root就等于x,直接返回所有节点的和tot_val即可;

如果root和查询的节点x的lca不为x,即root不是x的子树,显然我们直接对【in[x] , ou[x]】求区间和sum即可;

如果root和x的lca为x,那么我们找到x的子节点y使得y在root到x路径上,答案即tot_val - sum。


代码如下:


#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std ;typedef long long LL ;#pragma comment(linker, "/STACK:16777216")#define Log( i , a , b ) for ( int i = a ; ( 1 << i ) <= b ; ++ i )#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )#define travel( e , H , u ) for ( Edge* e = H[u] ; e ; e = e -> next )#define clr( a , x ) memset ( a , x , sizeof a )#define cpy( a , x ) memcpy ( a , x , sizeof a )const int LOGN = 15 ;const int MAXN = 10005 ;const int MAXE = 20005 ;struct Edge {int v ;Edge* next ;} E[MAXE] , *H[MAXN] , *edge ;int T[MAXN] ;int in[MAXN] , ou[MAXN] , dfs_clock ;int inc[MAXN][LOGN] ;int dep[MAXN] ;int val[MAXN] ;int tot_val ;int root ;int n , q ;void clear () {edge = E ;root = 1 ;tot_val = 0 ;dfs_clock = 0 ;clr ( H , 0 ) ;clr ( T , 0 ) ;}void addedge ( int u , int v ) {edge -> v = v ;edge -> next = H[u] ;H[u] = edge ++ ;}void dfs ( int u ) {in[u] = ++ dfs_clock ;travel ( e , H , u ) {int v = e -> v ;if ( v != inc[u][0] ) {inc[v][0] = u ;dep[v] = dep[u] + 1 ;dfs ( v ) ;}}ou[u] = dfs_clock ;}void preProcess () {dfs ( 1 ) ;For ( i , 1 , n ) Log ( j , 1 , n ) inc[i][j] = 0 ;Log ( j , 1 , n ) For ( i , 1 , n ) if ( inc[i][j - 1] ) inc[i][j] = inc[inc[i][j - 1]][j - 1] ;}int lca1 ( int x , int y ) {if ( dep[x] < dep[y] ) swap ( x , y ) ;int log = 0 ;Log ( i , 1 , dep[x] ) ++ log ;rev ( i , log , 0 ) if ( dep[x] - ( 1 << i ) >= dep[y] ) x = inc[x][i] ;if ( x == y ) return y ;rev ( i , log , 0 ) if ( inc[x][i] && inc[x][i] != inc[y][i] ) {x = inc[x][i] ;y = inc[y][i] ;}return inc[x][0] ;}int lca2 ( int x , int depth ) {int log = 0 ;Log ( i , 1 , dep[x] ) ++ log ;rev ( i , log , 0 ) if ( dep[x] - ( 1 << i ) >= depth ) x = inc[x][i] ;return x ;}void add ( int x , int v ) {for ( ; x <= n ; x += x & -x ) T[x] += v ;}int sum ( int x , int ans = 0 ) {for ( ; x ; x -= x & -x ) ans += T[x] ;return ans ;}void scanf ( int& x , char c = 0 ) {while ( ( c = getchar () ) < '0' || c > '9' ) ;x = c - '0' ;while ( ( c = getchar () ) >= '0' && c <= '9' ) x = x * 10 + c - '0' ;}void solve () {int x , y ;char op ;clear () ;scanf ( n ) ;rep ( i , 1 , n ) {scanf ( x ) , scanf ( y ) ;addedge ( x , y ) ;addedge ( y , x ) ;}preProcess () ;For ( i , 1 , n ) {scanf ( val[i] ) ;add ( in[i] , val[i] ) ;tot_val += val[i] ;}scanf ( q ) ;while ( q -- ) {op = getchar () ;scanf ( x ) ;if ( op == 'C' ) {scanf ( y ) ;tot_val += y - val[x] ;add ( in[x] , -val[x] ) ;add ( in[x] , val[x] = y ) ;} else if ( op == 'Q' ) {if ( root == x ) printf ( "%d\n" , tot_val ) ;else {int a = lca1 ( root , x ) ;if ( a != x ) printf ( "%d\n" , sum ( ou[x] ) - sum ( in[x] - 1 ) ) ;else {int b = lca2 ( root , dep[x] + 1 ) ;printf ( "%d\n" , tot_val - sum ( ou[b] ) + sum ( in[b] - 1 ) ) ;}}} else root = x ;}}int main () {int T , cas = 0 ;scanf ( "%d" , &T ) ;while ( T -- ) {printf ( "Case #%d:\n" , ++ cas ) ;solve () ;}return 0 ;}


0 0
原创粉丝点击