Loading

单($single$)

\(link\)
考场上看起来就比较像一个换根\(dp\),推了一把式子,拿了\(30pts\),然后没时间了。
问题1.
先进行一遍\(dfs\),搜出子树中权值和的大小和和子树中的\(b\)数组,设为\(s\)
然后在\(dfs\)一遍,换跟求出其他点的\(b\)数组,设为\(f\)
此时只有\(f[1]\)是正确的。我们考虑从上到下传递信息。

\[f[b]=f[b]+(f[a]-f[b]-sum[b]+sum[1]-sum[b])=f[a]+sum[1]-2*sum[b] \]

式子不难推,分两部分就完事了
问题2.
由于问题一求出来了\(f\)\(sum\)的关系式子,移项,可得

\[2*sum[b]-sum[1]=f[a]-f[b] \]

从上到下的时候可以求出\(2*sum[i]-sum[1]\),但是求不出\(2sum[1]-sum[1]\),因为他没有父节点。
考虑求出所有式子后相加,问题就解决了。

\[(2\sum_2^nsum[i])-(n-1)*sum[1] \]

考虑\(f\)数组的实际意义,可以发现上式第一项就是\(2f[1]\),带入后可以求出\(sum[1]\),进而求出\(sum[i]\)
\(dfs\)一边就可以求出权值

code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register int
#define printf Ruusupuu = printf
#define int long long

using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int N = 1e5 + 10 ;

int n , Ruusupuu ;

inline int read(){
	int w = 0 ; bool fg = 0 ; char ch = getchar() ;
	while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
	while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
	return fg ? -w : w ;
}

int T , cnt , t , head [N] , w [N] , f [N] , s [N] , x , y , c [N] ;

struct E{ int fr , to , next ; } a [N << 1] ;

inline void add( int f , int t ){
	a [++ cnt].fr = f ;
	a [cnt].to = t ;
	a [cnt].next = head [f] ;
	head [f] = cnt ;
}

void sc(){
	T = read() ;
}

inline void clear(){
	memset( head , -1 , sizeof( head ) ) ;
	memset( a , 0 , sizeof( a ) ) ;
	memset( f , 0 , sizeof( f ) ) ;
	memset( s , 0 , sizeof( s ) ) ;
	memset( c , 0 , sizeof( c ) ) ;
	cnt = 0 ;
}

void dfs( int x , int fa ){
	//printf( "%ld %ld\n" , x , fa ) ;
	for( R i = head [x] ; ~i ; i = a [i].next ){
		int y = a [i].to ; if( y == fa ) continue ;
		//printf( "%ld %ld\n" , x , y ) ; 
		dfs( y , x ) ; 
		f [x] += ( f [y] + s [y] ) ; 
		s [x] += s [y] ;
	} s [x] += w [x] ; 
}

inline void redfs( int x , int fa ){
//	printf( "RE%ld %ld\n" , x , fa ) ;
	if( fa ) f [x] = f [fa] - 2 * s [x] + s [1] ;
	for( R i = head [x] ; ~i ; i = a [i].next ){
		int y = a [i].to ; 
		
		if( y == fa ) continue ;
	//	printf( "xY%ld %ld\n" , x , y ) ;
		redfs( y , x ) ;
	}
}

inline void reredfs( int x , int fa ){
	if( fa ) c [x] = w [x] - w [fa] ; 
	for( R i = head [x] ; ~i ; i = a [i].next ){
		int y = a [i].to ;
		if( y == fa ) continue ;
		reredfs( y , x ) ;
	}
}

inline void rereredfs( int x , int fa ){
	bool fg = 0 ; f [x] = s [x] ;
	for( R i = head [x] ; ~i ; i = a [i].next ){
		int y = a [i].to ;
		if( y == fa ) continue ;
		rereredfs( y , x ) ;
		f [x] -= s [y] ; 
		fg = 1 ;
	}  if( !fg ) f [x] = s [x] ;
}

void work(){
	while( T -- ){
		clear() ;  n = read() ;
		for( R i = 1 ; i < n ; i ++ )
			x = read() , y = read() , add( x , y ) , add( y , x ) ;  
		t = read() ;
		
		if( t == 0 ){
			for( R i = 1 ; i <= n ; i ++ ) w [i] = read() ;
			dfs( 1 , 0 ) ;
			redfs( 1 , 0 ) ;
			for( R i = 1 ; i <= n ; i ++ )
				printf( "%lld " , f [i] ) ;
			puts( "" ) ;
		}
		else{
			for( R i = 1 ; i <= n ; i ++ ) w [i] = read() ;
			reredfs( 1 , 0 ) ; int anss = 0 ;
			for( R i = 2 ; i <= n ; i ++ ) anss += c [i] ; //printf( "C%lld\n" , w [1] ) ; 
			s [1] = ( anss + 2 * w [1] ) / ( n - 1 ) ; // printf( "%lld\n" , s [1] ) ;
			for( R i = 2 ; i <= n ; i ++ ) s [i] = ( s [1] - c [i] ) / 2 ;
		//	for( R i = 1 ; i <= n ; i ++ ) printf( "%lld\n" , s [i] ) ;
			rereredfs( 1 , 0 ) ;  
			for( R i = 1 ; i <= n ; i ++ ) printf( "%lld " , f [i] ) ;
			puts( "" ) ;
		}
	}
}

signed main(){
	sc() ;
	work() ;
	return 0 ; 
}

posted @ 2021-06-09 06:20  Soresen  阅读(82)  评论(0)    收藏  举报