单($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 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号