传送门:【HDU】4916 Count on the path
题目分析:首先我们将树转化成以1为根,这样对于每一个查询,如果该查询的路径不经过根(1),则答案就是1,否则我们再做讨论。
下面我们重点分析如何求解当查询的路径经过根(1)时。
首先我们先做一次dfs,求出以u为根的子树内的最小节点,用tree[u]表示。同时求出u的所有子树中最小和次小的tree[v],v是u的子节点,最小用sub_tree[u].m1表示,次小用sub_tree[u].m2表示。
然后再做一次dfs,求出如下信息:
1.求出除1外所有节点属于1的哪个节点的子树,用anc[u]保存(anc[1] = 1)。
2.假设路径anc[u]->u上经过的anc[u]的子节点为x,那么求出x->u的路径上除该路径上节点的最小节点编号,用dp[u]表示(dp[1] = INF)。
最后求出根(1)的最小v,次小v,第三小v。
然后每次查询分类讨论:
1.u==1&&v==1 -> ans=2
2.anc[u] == anc[v] -> ans = 1
3.u==1&&v!=1
如果tree[anc[v]] == m1 -> ans = min { sub_tree[v].m1,dp[v],m2 }
否则 ans = min { sub_tree[v].m1,dp[v],m1 }
4.u!=1&&v==1
如果tree[anc[u]] == m1 -> ans = min { sub_tree[u].m1,dp[],m2 }
否则 ans = min { sub_tree[u].m1,dp[u],m1 }5.u!=1&&v!=1
首先ans = min { sub_tree[u].m1,sub_tree[v].m1,dp[u],dp[v] }
1.如果tree[anc[u]] < m3 && tree[anc[v]] < m3,说明根的m1和m2都在路径上,只能用m3 -> ans = min(ans,m3)
2.不满足1则说明m1和m2中至少有一个不在路径中,假设m为不在路径中的那个 -> ans = min(ans,m)
代码如下:
#include <map> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std ; typedef long long LL ; #pragma comment ( linker , "/STACK:1024000000" ) #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 clr( a , x ) memset ( a , x , sizeof a ) const int MAXN = 1000005 ; const int MAXE = 2000005 ; const int INF = 0x3f3f3f3f ; struct Edge { int v , n ; Edge () {} Edge ( int v , int n ) : v ( v ) , n ( n ) {} } ; struct Node { int m1 , m2 ; inline void init () { m1 = m2 = INF ; } inline void update ( int val ) { if ( val < m1 ) { m2 = m1 ; m1 = val ; } else if ( val < m2 ) { m2 = val ; } } } ; Edge E[MAXE] ; Node sub_tree[MAXN] ; int tree[MAXN] ; int dp[MAXN] ; int p[MAXN] ; int anc[MAXN] ; int H[MAXN] , cntE ; int m1 , m2 , m3 ; int n , q ; inline void clear () { cntE = 0 ; clr ( H , -1 ) ; m1 = m2 = m3 = INF ; } inline void addedge ( int u , int v ) { E[cntE] = Edge ( v , H[u] ) ; H[u] = cntE ++ ; } inline void update ( int val ) { if ( val < m1 ) { m3 = m2 ; m2 = m1 ; m1 = val ; } else if ( val < m2 ) { m3 = m2 ; m2 = val ; } else if ( val < m3 ) { m3 = val ; } } void dfs1 ( int u , int fa ) { tree[u] = u ; sub_tree[u].init () ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if( v == fa ) continue ; dfs1 ( v , u ) ; sub_tree[u].update ( tree[v] ) ; tree[u] = min ( tree[u] , tree[v] ) ; } } void dfs2 ( int u , int fa , int it ) { anc[u] = it ; for ( int i = H[u] ; ~i ; i = E[i].n ) { int v = E[i].v ; if ( v == fa ) continue ; dp[v] = dp[u] ; if ( tree[v] != sub_tree[u].m1 ) dp[v] = min ( dp[v] , sub_tree[u].m1 ) ; else dp[v] = min ( dp[v] , sub_tree[u].m2 ) ; dfs2 ( v , u , it ) ; } } void debug () { printf ( "tree:\n" ) ; For ( i , 1 , n ) printf ( "%d: %d\n" , i , tree[i] ) ; printf ( "sub_tree:\n" ) ; printf ( "1: %d %d %d\n" , m1 , m2 , m3 ) ; For ( i , 2 , n ) printf ( "%d: %d %d\n" , i , sub_tree[i].m1 , sub_tree[i].m2 ) ; printf ( "dp:\n" ) ; For ( i , 1 , n ) printf ( "%d: %d\n" , i , dp[i] ) ; printf ( "anc:\n" ) ; For ( i , 1 , n ) printf ( "%d: %d\n" , i , anc[i] ) ; } inline 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 u , v , ans ; clear () ; rep ( i , 1 , n ) { scanf ( u ) ; scanf ( v ) ; addedge ( u , v ) ; addedge ( v , u ) ; } for ( int i = H[1] ; ~i ; i = E[i].n ) { v = E[i].v ; dfs1 ( v , 1 ) ; update ( tree[v] ) ; } anc[1] = 1 ; for ( int i = H[1] ; ~i ; i = E[i].n ) { v = E[i].v ; dp[v] = INF ; dfs2 ( v , 1 , v ) ; } //debug () ; rep ( i , 0 , q ) { scanf ( u ) ; scanf ( v ) ; if ( i ) { u ^= ans ; v ^= ans ; } if ( u == 1 && v == 1 ) ans = 2 ; else if ( anc[u] == anc[v] ) ans = 1 ; else if ( u == 1 ) { ans = min ( sub_tree[v].m1 , dp[v] ) ; if ( tree[anc[v]] == m1 ) ans = min ( ans , m2 ) ; else ans = min ( ans , m1 ) ; } else if ( v == 1 ) { ans = min ( sub_tree[u].m1 , dp[u] ) ; if ( tree[anc[u]] == m1 ) ans = min ( ans , m2 ) ; else ans = min ( ans , m1 ) ; } else { ans = min ( sub_tree[u].m1 , sub_tree[v].m1 ) ; ans = min ( ans , dp[u] ) ; ans = min ( ans , dp[v] ) ; if ( tree[anc[u]] < m3 && tree[anc[v]] < m3 ) { ans = min ( ans , m3 ) ; } else { if ( tree[anc[v]] == m1 || tree[anc[u]] == m1 ) ans = min ( ans , m2 ) ; else ans = min ( ans , m1 ) ; } } printf ( "%d\n" , ans ) ; } } int main () { while ( ~scanf ( "%d%d" , &n , &q ) ) solve () ; return 0 ; }