題目鏈接:CodeVS1218
題目大意
大小爲
分析
1. 對於所有的軍隊,越往上,顯然能封鎖的節點就越多;時間越多,能往上跑的距離就越多;所以二分時間。
2. 有一些軍隊,可以跨過根節點而控制根節點的其他子節點( 以下簡稱爲子節點 )。
3. 對於不能跨根節點的軍隊( 包括不能到根和剛好能到根 ),直接在停止處標記;而那些可以跨根的軍隊,要記錄起來( 記爲
4. 對於子節點,其是否需要從跟節點調用一支軍隊來控制可以通過一次dfs搜索判斷;需要軍隊的記錄下來( 記爲
5. 先把
6. 然而,當前的
6.5 本人當時用了一個非常低效的匹配方法,導致無限T,因此開了一些優化,比如倍增(其實不倍增並不會慢多少)。
上代碼
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std ;
const int N = 5e4 + 10 ;
const int M = 30 + 10 ;
int n, m, tot ;
struct node_edge {
int to, val ;
} ;
vector < node_edge > edge[ N ] ;
struct node_army { // 記錄軍隊
int plc, time, nown ; // 起始位置,剩餘時限,目前位置
// 其中plc是不變的,而time和nown是變化的
} army[ N ] ;
// dfs一棵樹
// fa[i][j]表示i的 2^j 祖先,所以fa[i][0]即爲i的父親
int fa[ N ][ M ], dist[ N ] ;
void dfs( int a , int b ) {
fa[ a ][ 0 ] = b ;
for ( int i = 0 ; i < edge[ a ].size() ; i ++ ) {
int node = edge[ a ][ i ].to ;
if ( node == b ) continue ;
dist[ node ] = dist[ a ] + edge[ a ][ i ].val ;
dfs( node , a ) ;
}
}
// 爲了優化,我連倍增都用了,當時無限T的心情可以腦補
// 樹上倍增
inline void calc_fa() {
for ( int j = 1 ; ; j ++ ) {
int flag = false ;
for ( int i = 1 ; i <= n ; i ++ ) {
int node = fa[ i ][ j - 1 ] ;
if ( !fa[ node ][ j - 1 ] ) continue ;
flag = true ; fa[ i ][ j ] = fa[ node ][ j - 1 ] ;
}
if ( !flag ) return ;
}
}
// 讀入優化,說多了都是淚
inline void get_num( int &a ) {
char ch ;
while ( ch = getchar(), ch >= '0' && ch <= '9' )
a = a * 10 + ch - '0' ;
return ;
}
inline void init() {
scanf( "%d", &n ) ; getchar() ;
for ( int i = 1 ; i < n ; i ++ ) {
int a = 0, b = 0, c = 0 ;
get_num( a ), get_num( b ), get_num( c ) ;
edge[ a ].push_back( (node_edge){ b , c } ) ;
edge[ b ].push_back( (node_edge){ a , c } ) ;
tot += c ;
}
dfs( 1 , 0 ), calc_fa() ;
scanf( "%d", &m ) ; getchar() ;
for ( int i = 1 ; i <= m ; i ++ )
get_num( army[ i ].plc ) ;
}
bool book[ N ] ; // 封鎖標記
int lx, ly ;
struct node_xxyy {
int from, val ;
// 對X爲軍隊的來源和剩餘時間
// 對Y爲子節點和距離
inline bool operator < ( const node_xxyy a ) const {
return val < a.val ;
}
} x[ N ], y[ N ] ;
inline void go_up( int a ) {
int node = army[ a ].nown ;
while ( fa[ node ][ 0 ] != 1 ) {
int k = 0 ;
while ( fa[ node ][ k ] != 1 && fa[ node ][ k ] != 0 ) {
if ( dist[ node ] - dist[ fa[ node ][ k ] ] <= army[ a ].time )
k ++ ;
else break ;
}
if ( k == 0 ) {
book[ army[ a ].nown = node ] = true ; return ;
} else {
army[ a ].time -= dist[ node ] - dist[ fa[ node ][ k - 1 ] ] ;
army[ a ].nown = node = fa[ node ][ k - 1 ] ;
}
}
if ( army[ a ].time <= dist[ army[ a ].nown ] )
book[ army[ a ].nown ] = true ;
return ;
}
bool check( int a ) {
if ( book[ a ] ) return true ;
for ( int i = 0 ; i < edge[ a ].size() ; i ++ ) {
int node = edge[ a ][ i ].to ;
if ( node == fa[ a ][ 0 ] ) continue ;
if ( !check( node ) ) return false ;
}
if ( edge[ a ].size() > 1 ) {
book[ a ] = true ; return true ; //優化之一
} else
return false ;
}
inline bool judge( int valn ) {
for ( int i = 1 ; i <= m ; i ++ )
army[ i ].time = valn, army[ i ].nown = army[ i ].plc ;
for ( int i = 1 ; i <= m ; i ++ ) {
go_up( i ) ;
if ( army[ i ].time > dist[ army[ i ].nown ] ) // 說明可以越根
x[ ++ lx ] = (node_xxyy){ army[ i ].nown , army[ i ].time - dist[ army[ i ].nown ] } ;
}
for ( int i = 0 ; i < edge[ 1 ].size() ; i ++ )
if ( !check( edge[ 1 ][ i ].to ) )
y[ ++ ly ] = (node_xxyy){ edge[ 1 ][ i ].to , dist[ edge[ 1 ][ i ].to ] } ;
if ( lx < ly ) return false ; // 剪枝
sort( x + 1 , x + lx + 1 ) ; sort( y + 1 , y + ly + 1 ) ;
int mark = 1 ;
for ( int i = 1 ; i <= lx ; i ++ ) { //我T就是T在這個匹配,我原來的版本太low了:在Y中upper_bound()
if ( !book[ x[ i ].from ] ) {
book[ x[ i ].from ] = true ; continue ;
} else {
while ( book[ y[ mark ].from ] && mark < ly ) mark ++ ;
if ( x[ i ].val >= y[ mark ].val ) {
book[ y[ mark ].from ] = true ;
mark ++ ;
}
}
}
for ( int i = 1 ; i <= ly ; i ++ )
if ( !check( y[ i ].from ) ) return false ;
return true ;
}
inline int figure() {
if ( m < edge[ 1 ].size() ) return -1 ; // 唯一無法封鎖的情況
int ans ;
int l = 1, r = tot, mid ;
while ( l <= r ) {
lx = ly = 0 ;
memset( book , 0 , sizeof( book ) ) ;
mid = ( l + r ) >> 1 ;
if ( judge( mid ) )
r = mid - 1, ans = mid ;
else
l = mid + 1 ;
}
return ans ;
}
int main() {
init() ;
printf( "%d\n", figure() ) ;
return 0 ;
}
以上