我们先处理出每一条边会对花费产生几次贡献。然后把每一条边按照:进行一次操作减去的花费,从大到小放出大根堆中。不断取出堆中最大,减去变小的贡献,然后重新放入贡献变小后的这个元素。直至符合条件。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N= 1e5 + 5 ;
int T, n, s, u, v, w, ans, sum;
int size[ N] ;
int cnt, head[ N] ;
struct edge{ int next, to, w, t; } e[ N<< 1 ] ;
struct node
{
int t, w, v;
inline bool operator < ( const node & x) const
{
return x. v> v;
}
} ;
inline void add ( int u, int v, int w)
{
cnt++ ;
e[ cnt] . next= head[ u] ;
e[ cnt] . to= v;
e[ cnt] . w= w;
e[ cnt] . t= 0 ;
head[ u] = cnt;
}
void dfs ( int u, int fa)
{
bool jay= true ;
for ( register int i= head[ u] ; i; i= e[ i] . next)
if ( e[ i] . to!= fa)
{
jay= false ;
dfs ( e[ i] . to, u) ;
e[ i] . t= size[ e[ i] . to] ;
size[ u] + = size[ e[ i] . to] ;
}
if ( jay) size[ u] = 1 ;
}
priority_queue< node> q;
signed main ( ) {
scanf ( "%lld" , & T) ;
while ( T-- )
{
scanf ( "%lld%lld" , & n, & s) ;
sum= 0 ;
while ( q. size ( ) ) q. pop ( ) ;
cnt= 0 ;
for ( register int i= 1 ; i<= n; ++ i) head[ i] = 0 ;
for ( register int i= 1 ; i<= n; ++ i) size[ i] = 0 ;
for ( register int i= 1 ; i< n; ++ i)
{
scanf ( "%lld%lld%lld" , & u, & v, & w) ;
add ( u, v, w) ;
add ( v, u, w) ;
}
dfs ( 1 , 0 ) ;
for ( register int i= 1 ; i<= cnt; ++ i)
if ( e[ i] . t)
{
sum+ = e[ i] . t* e[ i] . w;
int del= ( e[ i] . w- e[ i] . w/ 2 ) * e[ i] . t;
q. push ( ( node) { e[ i] . t, e[ i] . w/ 2 , del} ) ;
}
ans= 0 ;
while ( sum> s)
{
node u= q. top ( ) ; q. pop ( ) ;
sum- = u. v;
int del= ( u. w- u. w/ 2 ) * u. t;
q. push ( ( node) { u. t, u. w/ 2 , del} ) ;
ans++ ;
}
printf ( "%lld\n" , ans) ;
}
return 0 ;
}