传送门:【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 ;
}