E1 - Weights Division (easy version)
E1 - Weights Division (easy version)
题意:给定一个带权无环联通图(编号为1的节点是这颗树的根),每一次可以选择一条边,将这条边的权值变成原来的1/2,向下取整。问:当根节点到所有叶子节点的距离的和小于等于题目要求的S时,最少操作次数是?
AC_Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define endl '\n' 5 const ll mod=1e9+7; 6 const int maxn = 1e5+10; 7 8 vector<ll>w,cnt; //w[i]表示i边的权值; cnt[i]表示i边所影响的路径有几个 9 vector<vector<pair<ll,ll>>>g; 10 11 ll getdiff(ll i){ //算i边缩小一半后对整个答案造成的影响 12 return w[i]*1ll*cnt[i]-(w[i]/2)*1ll*cnt[i]; 13 } 14 15 void dfs(ll v, ll fa=-1){ //fa表示v与它的父亲连的那条边的编号 16 if( g[v].size()==1 && fa!=-1 ){ //v是叶子节点 17 cnt[fa]=1; 18 return ; 19 } 20 21 for( auto i: g[v] ){ 22 if( i.second==fa ) continue; 23 dfs(i.first,i.second); 24 if( fa!=-1 ){ 25 cnt[fa]+=cnt[i.second]; 26 } 27 } 28 } 29 30 ll n,s; 31 int main() 32 { 33 int t;cin>>t; 34 while( t-- ){ 35 cin>>n>>s; 36 w = cnt = vector<ll>(n-1); 37 g = vector<vector<pair<ll,ll>>>(n+1); 38 for(int i=0;i<n-1;i++){ 39 ll x,y; cin>>x>>y>>w[i]; 40 g[x].push_back({y,i}); //存连接点和边的编号 41 g[y].push_back({x,i}); 42 } 43 44 dfs(1); //dfs一遍求出每个边所能影响的root-->leaves路径有多少条(也就是每个边对最后值的贡献是多少) 45 46 set<pair<ll,ll>>st; //set自动按getdiff的大小从小到大排序 47 ll cur=0; 48 for(int i=0;i<n-1;i++){ //预处理 49 st.insert({getdiff(i),i}); 50 cur+=w[i]*1ll*cnt[i]; 51 } 52 53 ll ans=0; 54 while(cur>s){ 55 int id=st.rbegin()->second; //rbegin:集合里的最后一个元素 56 st.erase(prev(st.end())); //删除集合里的最后一个元素 57 cur-=getdiff(id); 58 w[id]/=2; 59 st.insert({getdiff(id),id}); 60 ans++; 61 } 62 cout<<ans<<endl; 63 } 64 return 0; 65 }