【HDU】4916 Count on the path 树型DP

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


你可能感兴趣的:(HDU)