说在前面
在ruc自习的第一天(此处应当@Narcissus)
原本在图书馆订了房,今天突然被告知图书馆放假了
不仅进不去,还要因为没有按时报道扣信用,神操作
(后来官方发了通知,扣的信用会在周一清掉)
感觉大家的生活都好颓废
希望开学会好起来
题目
LOJ2952传送门
看题戳传送门
解法
部分分给足了提示
最小值最大显然二分答案
对于一条链的情况,直接按mid切就好
菊花图的情况,大于mid的边直接计入答案,小于mid的两两匹配,要匹配数最大。不难发现,小配大是最优策略。
一棵树的情况,就是把以上两种合起来,并且把没有匹配到的最长的链向上传,用个map可以轻松实现
详见代码
下面是自带大长度的代码
#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , M , head[50005] , tp ;
struct Path{
int pre , to , len ;
}p[100005] ;
void In( int t1 , int t2 , int t3 ){
p[++tp] = ( Path ){ head[t1] , t2 , t3 } , head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 , t3 } , head[t2] = tp ;
}
int f[50005] , g[50005] , limit , sta[50005] , topp ;
map<int,int> cnt ;
int get_leval( int x ){
int L = 1 , R = topp , mid , rt = 0x3f3f3f3f ;
while( L <= R ){
mid = ( L + R ) >> 1 ;
if( sta[mid] < x ) L = mid + 1 ;
else rt = sta[mid] , R = mid - 1 ;
} return rt ;
}
void dfs( int u , int fa ){
f[u] = 0 , g[u] = 0 ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == fa ) continue ;
dfs( v , u ) , f[u] += f[v] ;
}
int siz = 0 , now , tmp = 0 ;
topp = 0 , cnt.clear() ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to , len = p[i].len + g[v] ;
if( v == fa ) continue ;
if( len >= limit ){
f[u] ++ ; continue ;
} else if( cnt.count( len ) == 0 ){
cnt[len] = 1 , sta[++topp] = len ;
} else cnt[len] ++ ;
siz ++ ;
} sort( sta + 1 , sta + topp + 1 ) ;
map<int,int>::iterator Lpt , Rpt ;
while( siz > 1 ){
Lpt = cnt.begin() , now = Lpt->first ;
if( ( -- Lpt->second ) == 0 ) cnt.erase( Lpt ) ;
siz -- ;
Rpt = cnt.lower_bound( get_leval( limit - Lpt->first ) ) ;
if( Rpt == cnt.end() ){
tmp = now ;
continue ;
} if( ( -- Rpt->second ) == 0 ) cnt.erase( Rpt ) ;
siz -- , f[u] ++ ;
} g[u] = ( siz == 1 ? cnt.begin()->first : tmp ) ;
}
void solve(){
int L = 0 , R = 49999 * 10000 , ans ;
while( L <= R ){
limit = ( L + R ) >> 1 ;
dfs( 1 , 1 ) ;
if( f[1] >= M ) ans = limit , L = limit + 1 ;
else R = limit - 1 ;
} printf( "%d" , ans ) ;
}
int main(){
freopen( "track.in" , "r" , stdin ) ;
freopen( "track.out", "w" , stdout) ;
scanf( "%d%d" , &N , &M ) ;
for( int i = 1 , u , v , L ; i < N ; i ++ ){
scanf( "%d%d%d" , &u , &v , &L ) ;
In( u , v , L ) ;
} solve() ;
}