【HDU】5156 Harry and Christmas tree 【lca】

传送门:【HDU】5156 Harry and Christmas tree


题目分析:每一种颜色我们分开考虑他们对所有节点的贡献,对于两个颜色同为c的节点u和v(假设u!=v),那么在lca(u,v)的时候我们需要-1,因为在lca(u,v)一直到根的路径上,颜色c只能影响一次。基于此,我们对每种颜色的所有节点按照dfs序排好序,首先每个节点+1,然后对dfs序相邻的两个节点(注意颜色要相同)求一次lca,在lca这个位置-1,最后dfs一次将儿子的贡献累加上来就得到了每种颜色对自己的贡献了。

复杂度O(n+m),常数较大。


代码如下:


#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;

typedef long long LL ;

#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 )
#define cpy( a , x ) memcpy ( a , x , sizeof a )

const int MAXN = 50005 ;
const int MAXE = 2100005 ;

struct Edge {
	int v , n ;
	Edge () {}
	Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;

Edge E[MAXE] ;
int H[MAXN] , cntE ;
int A[MAXN] , B[MAXN << 1] , Q[MAXN] ;
int vis[MAXN] ;
int num[MAXN] ;
int p[MAXN] ;
int n , m ;

void clear () {
	cntE = 1 ;
	clr ( A , 0 ) ;
	clr ( B , 0 ) ;
	clr ( Q , 0 ) ;
	clr ( H , 0 ) ;
	clr ( vis , 0 ) ;
	clr ( num , 0 ) ;
}

int find ( int x ) {
	int tmp , ans , o = x ;
	while ( p[x] != x ) x = p[x] ;
	ans = x , x = o ;
	while ( p[x] != x ) {
		tmp = p[x] ;
		p[x] = ans ;
		x = tmp ;
	}
	return ans ;
}

void addedge ( int u , int v , int H[] ) {
	E[cntE] = Edge ( v , H[u] ) ;
	H[u] = cntE ++ ;
}

void dfs ( int u , int f = 0 ) {
	for ( int i = A[u] ; i ; i = E[i].n ) addedge ( E[i].v , u , B ) ;
	for ( int i = H[u] ; i ; i = E[i].n ) if ( E[i].v != f ) dfs ( E[i].v , u ) ;
}

void tarjan ( int u , int f = 0 ) {
	p[u] = u ;
	vis[u] = 1 ;
	for ( int i = Q[u] ; i ; i = E[i].n ) if ( vis[E[i].v] ) -- num[find ( E[i].v )] ;
	for ( int i = H[u] ; i ; i = E[i].n ) {
		int v = E[i].v ;
		if ( vis[v] ) continue ;
		tarjan ( v , u ) ;
		p[v] = u ;
	}
	for ( int i = H[u] ; i ; i = E[i].n ) {
		int v = E[i].v ;
		if ( v == f ) continue ;
		num[u] += num[v] ;
	}
}

void scanf ( int& x , char c = 0 ) {
	while ( ( c = getchar () ) < '0' ) ;
	x = c - '0' ;
	while ( ( c = getchar () ) >= '0' ) x = x * 10 + c - '0' ;
}

void solve () {
	int u , v ;
	clear () ;
	rep ( i , 1 , n ) {
		scanf ( u ) ;
		scanf ( v ) ;
		addedge ( u , v , H ) ;
		addedge ( v , u , H ) ;
	}
	For ( i , 1 , m ) {
		scanf ( u ) ;
		scanf ( v ) ;
		addedge ( u , v , A ) ;
		++ num[u] ;
	}
	dfs ( 1 ) ;
	For ( i , 1 , 100000 ) if ( B[i] ) {
		u = 0 ;
		for ( int j = B[i] ; j ; j = E[j].n ) {
			v = E[j].v ;
			if ( u ) {
				if ( u != v ) {
					addedge ( u , v , Q ) ;
					addedge ( v , u , Q ) ;
				} else -- num[v] ;
			}
			u = v ;
		}
	}
	tarjan ( 1 ) ;
	For ( i , 1 , n ) printf ( "%d%c" , num[i] , i < n ? ' ' : '\n' ) ;
}

int main () {
	while ( ~scanf ( "%d%d" , &n , &m ) ) solve () ;
	return 0 ;
}


你可能感兴趣的:(HDU)