思路
分析最优解性质
任意两个点高度至多相差1 任取一条最优滑雪路径。最后反复出现的点一定最多仅有2个。其余的路径上的点互不相同 。
若不然,可以将其余的重复点构成的路径加到这两个点的反复中。
如果能反复,考虑在点uu u 开始进行反复。开始点为点v。则最长能滑动的总路径为2hv−hu2h_v - h_u 2 h v − h u 这是因为从点v到点u多余能量hv−huh_v - h_u h v − h u ,在u点开始与其邻居进行反复,直到能量消耗为0.至此,共消耗能量2(hv−hu)2 (h _v - h_u) 2 ( h v − h u ) 。加上从u点到doge能滑动最长的距离huh_u h u 。 由上式可见,若huh_u h u 较小,则滑动的距离较大。因此对每个结点找其能到达的高度最低的u点 ,如果能找到答案为上述式子,否则答案为自身的高度
逆向考察
对上述u点,其必须满足至少有一个邻居与其有同样的高度。对于这样的点对u,vu,v u , v ,v是u的与其相同高度的邻居。其到达它们最近的doge的路径互不相交。因此∑u∈Shu\sum_{u \in S} h_u u ∈ S ∑ h u 较小。可以证明其是O(n)O(n) O ( n ) 级别的。于是不同的huh_u h u 个数是n\sqrt{n} n 级别的。 对每种可能的高度对应的结点考察其能够到达的所有结点。
实现(官方)
while ( ! q. empty ( ) ) {
int x= q. front ( ) ; q. pop ( ) ;
for ( auto c: adj[ x] ) {
if ( d[ c] == - 1 ) {
d[ c] = d[ x] + 1 ;
q. push ( c) ;
}
}
}
利用h数组记录可行的高度i是几号高度,利用g数组记录z号高度的实际高度。
for ( int i= 1 ; i<= n ; i++ ) {
f[ d[ i] ] . push_back ( i) ;
for ( auto c: adj[ i] ) {
if ( d[ c] == d[ i] && c> i) {
use[ d[ i] ] = true ;
}
}
}
for ( int i= 0 ; i<= n ; i++ ) {
if ( use[ i] ) {
g[ ++ z] = i;
h[ i] = z;
}
}
ans[i][z]表示i号结点到达z号高度满足邻居有相同z号高度的结点所需要的最少初始能量,其中z的取值是n\sqrt{n} n 级别的。 将结点按高度进行分层。假设下一层所需要到达的每一种可能高度的最低能量已经求出,下一层对上一层按照公式:
ans[x][i]=min(ans[x][i],max(0,ans[c][i]−1))ans[x][i]=min(ans[x][i],max(0,ans[c][i]-1)) a n s [ x ] [ i ] = m i n ( a n s [ x ] [ i ] , m a x ( 0 , a n s [ c ] [ i ] − 1 ) )
其中c是下一层结点,x是当前层结点。
for ( auto c: adj[ x] ) {
if ( d[ c] == d[ x] - 1 ) {
for ( int i= 1 ; i<= z ; i++ ) ans[ x] [ i] = min ( ans[ x] [ i] , max ( ( ll) 0 , ans[ c] [ i] - 1 ) ) ;
}
}
同层结点的转移,利用up and down dp ,通过两次dfs(待学习)
ans[c][i]=min(ans[c][i],ans[id][i]+1)ans[c][i]=min(ans[c][i],ans[id][i]+1) a n s [ c ] [ i ] = m i n ( a n s [ c ] [ i ] , a n s [ i d ] [ i ] + 1 )
其中id是c的邻居,对每种高度i循环执行
void dfs ( int id, int p) {
vis[ id] = true ;
for ( auto c: adj[ id] ) {
if ( c== p || d[ c] != d[ id] ) continue ;
dfs ( c, id) ;
for ( int i= 1 ; i<= z ; i++ ) {
ans[ id] [ i] = min ( ans[ id] [ i] , ans[ c] [ i] + 1 ) ;
}
ans[ id] [ h[ d[ id] ] ] = 0 ;
}
}
void dfs2 ( int id, int p) {
for ( auto c: adj[ id] ) {
if ( c== p || d[ c] != d[ id] ) continue ;
for ( int i= 1 ; i<= z ; i++ ) {
ans[ c] [ i] = min ( ans[ c] [ i] , ans[ id] [ i] + 1 ) ;
}
ans[ c] [ h[ d[ c] ] ] = 0 ;
dfs2 ( c, id) ;
}
}
# include <bits/stdc++.h>
using namespace std;
typedef long long ll;
# define fi first
# define se second
# define int long long
const ll mod= 998244353 ;
const int N= 2e5 + 1 ;
int n;
int d[ N] ;
queue< int > q;
vector< int > adj[ N] ;
int g[ N] , h[ N] , z;
bool use[ N] ;
vector< int > ans[ N] ;
vector< int > f[ N] ;
bool vis[ N] ;
void dfs ( int id, int p) {
vis[ id] = true ;
for ( auto c: adj[ id] ) {
if ( c== p || d[ c] != d[ id] ) continue ;
dfs ( c, id) ;
for ( int i= 1 ; i<= z ; i++ ) {
ans[ id] [ i] = min ( ans[ id] [ i] , ans[ c] [ i] + 1 ) ;
}
ans[ id] [ h[ d[ id] ] ] = 0 ;
}
}
void dfs2 ( int id, int p) {
for ( auto c: adj[ id] ) {
if ( c== p || d[ c] != d[ id] ) continue ;
for ( int i= 1 ; i<= z ; i++ ) {
ans[ c] [ i] = min ( ans[ c] [ i] , ans[ id] [ i] + 1 ) ;
}
ans[ c] [ h[ d[ c] ] ] = 0 ;
dfs2 ( c, id) ;
}
}
main ( ) {
ios:: sync_with_stdio ( false ) ; cin. tie ( 0 ) ;
cin >> n;
for ( int i= 1 ; i<= n ; i++ ) {
int x; cin >> x;
if ( x== 1 ) { q. push ( i) ; d[ i] = 0 ; }
else d[ i] = - 1 ;
}
for ( int i= 1 ; i< n ; i++ ) {
int u, v; cin >> u >> v;
adj[ u] . push_back ( v) ;
adj[ v] . push_back ( u) ;
}
while ( ! q. empty ( ) ) {
int x= q. front ( ) ; q. pop ( ) ;
for ( auto c: adj[ x] ) {
if ( d[ c] == - 1 ) {
d[ c] = d[ x] + 1 ;
q. push ( c) ;
}
}
}
for ( int i= 1 ; i<= n ; i++ ) {
f[ d[ i] ] . push_back ( i) ;
for ( auto c: adj[ i] ) {
if ( d[ c] == d[ i] && c> i) {
use[ d[ i] ] = true ;
}
}
}
for ( int i= 0 ; i<= n ; i++ ) {
if ( use[ i] ) {
g[ ++ z] = i;
h[ i] = z;
}
}
for ( int i= 1 ; i<= n ; i++ ) {
ans[ i] . resize ( z+ 1 ) ;
}
for ( int j= 0 ; j<= n ; j++ ) {
for ( auto x: f[ j] ) {
for ( int i= 1 ; i<= z ; i++ ) ans[ x] [ i] = 1e9 ;
for ( auto c: adj[ x] ) {
if ( d[ c] == d[ x] - 1 ) {
for ( int i= 1 ; i<= z ; i++ ) ans[ x] [ i] = min ( ans[ x] [ i] , max ( ( ll) 0 , ans[ c] [ i] - 1 ) ) ;
}
}
}
for ( auto x: f[ j] ) {
if ( ! vis[ x] ) {
dfs ( x, 0 ) ;
dfs2 ( x, 0 ) ;
}
}
}
for ( int i= 1 ; i<= n ; i++ ) {
int res= d[ i] ;
for ( int j= 1 ; j<= z ; j++ ) {
if ( ans[ i] [ j] == 0 ) res= max ( res, d[ i] * 2 - g[ j] ) ;
}
cout << res << ' ' ;
}
cout << '\n' ;
}