生活随笔
收集整理的這篇文章主要介紹了
CF1654-G. Snowy Mountain(2900) GOOD
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
思路
分析最優解性質
任意兩個點高度至多相差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' ; }
總結
以上是生活随笔 為你收集整理的CF1654-G. Snowy Mountain(2900) GOOD 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。