原题链接:http://codeforces.com/problemset/problem/1399/E2

Weights Division (hard version)

Easy and hard versions are actually different problems, so we advise you to read both statements carefully.

You are given a weighted rooted tree, vertex 1 is the root of this tree. Also, each edge has its own cost.

A tree is a connected graph without cycles. A rooted tree has a special vertex called the root. A parent of a vertex v is the last different from v vertex on the path from the root to the vertex v. Children of vertex v are all vertices for which v is the parent. A vertex is a leaf if it has no children. The weighted tree is such a tree that each edge of this tree has some weight.

The weight of the path is the sum of edges weights on this path. The weight of the path from the vertex to itself is 0.

You can make a sequence of zero or more moves. On each move, you select an edge and divide its weight by 2 rounding down. More formally, during one move, you choose some edge i and divide its weight by 2 rounding down (wi:=⌊wi2⌋).

Each edge i has an associated cost ci which is either 1 or 2 coins. Each move with edge i costs ci coins.

Your task is to find the minimum total cost to make the sum of weights of paths from the root to each leaf at most S. In other words, if w(i,j) is the weight of the path from the vertex i to the vertex j, then you have to make ∑v∈leavesw(root,v)≤S, where leaves is the list of all leaves.

You have to answer t independent test cases.

Input

The first line of the input contains one integer t (1≤t≤2⋅104) — the number of test cases. Then t test cases follow.

The first line of the test case contains two integers n and S (2≤n≤105;1≤S≤1016) — the number of vertices in the tree and the maximum possible sum of weights you have to obtain. The next n−1 lines describe edges of the tree. The edge i is described as four integers vi, ui, wi and ci (1≤vi,ui≤n;1≤wi≤106;1≤ci≤2), where vi and ui are vertices the edge i connects, wi is the weight of this edge and ci is the cost of this edge.

It is guaranteed that the sum of n does not exceed 105 (∑n≤105).

Output

For each test case, print the answer: the minimum total cost required to make the sum of weights paths from the root to each leaf at most S.

Example
input

4
4 18
2 1 9 2
3 2 4 1
4 1 1 2
3 20
2 1 8 1
3 1 7 2
5 50
1 3 100 1
1 5 10 2
2 3 123 2
5 4 55 1
2 100
1 2 409 2

output

0
0
11
6

题目大意

与CF1399E1类似,但每条边进行操作的代价不等,操作一次代价为111或222,要求求出使所有叶子节点到根的路径的权值之和≤\le≤给定值的最小代价。

题解

这道题告诉我,能枚举的就不要瞎jb贪心……

本来想的是把代价为111的边和代价为222的边分别放进优先队列后,比较下列三种情况:操作一条最“赚”的、代价为222的边;操作最“赚”的、代价为111的边两遍;操作最“赚”的和次“赚”的代价为111的边各一遍。除了这个贪心还有一堆边界,讨论傻了以后在第212121个点被莫名卡了,不知道有没有同学知道问题在哪儿。

之后就是更暴力但有效的做法,用两个优先队列分别模拟一遍操作最“赚”的边直到满足≤s\le s≤s或者所有边都被操作成000,将每次减掉的值做一个前缀和。因为我们的总操作必定是由操作一堆代价为111的边和代价为222的边组合起来的,而我们求出的前缀和在对应的代价里都是最优解,所以最优的操作就是将两个前缀和的一部分(这一部分可以为空)组合起来,我们用两个指针不断取minminmin就能找到最终答案。

代码

第二段代码为贪心被卡版本,有兴趣的网友可以交流♂一下。

#include<bits/stdc++.h>
#define L long long
using namespace std;
const int M=1e5+5;
const int N=2e6+5;
struct sd{int to,wei,cst;};
struct edg{int tim,wei;L val;bool operator <(const edg &x)const{return x.val>val;}
};
int t,n,ans=1e7,t1,t2,p1,p2;
L tot,s;
L pre1[N],pre2[N];
vector<sd>mmp[M];
priority_queue<edg>dui1;
priority_queue<edg>dui2;
bool vis[M];
void re()
{for(int i=0;i<=t1;++i)pre1[i]=0;for(int i=0;i<=t2;++i)pre2[i]=0;ans=1e7,tot=t1=t2=0;for(int i=1;i<=n;++i)vis[i]=0;for(int i=1;i<=n;++i)mmp[i].erase(mmp[i].begin(),mmp[i].end());for(;!dui1.empty();dui1.pop());for(;!dui2.empty();dui2.pop());
}
void in()
{int a,b,c,d;scanf("%d%I64d",&n,&s);for(int i=1;i<n;++i){scanf("%d%d%d%d",&a,&b,&c,&d);mmp[a].push_back((sd){b,c,d});mmp[b].push_back((sd){a,c,d});}
}
int dfs(int v)
{L tmp,re=0;int to,wei;edg add;vis[v]=1;if(mmp[v].size()==1&&v!=1)return 1;for(int i=mmp[v].size()-1;i>=0;--i){if(vis[mmp[v][i].to])continue;to=mmp[v][i].to,wei=mmp[v][i].wei;tmp=dfs(to);add.tim=tmp,add.wei=wei,add.val=tmp*(wei-wei/2);mmp[v][i].cst==1?dui1.push(add):dui2.push(add);tot+=tmp*wei;re+=tmp;}return re;
}
void ac()
{dfs(1);if(tot<=s){printf("0\n");return;}edg tmp;for(;!dui1.empty();){tmp=dui1.top();++t1,pre1[t1]=tmp.val+pre1[t1-1];if(tot-pre1[t1]<=s)break;tmp.wei>>=1,tmp.val=tmp.tim*1ll*(tmp.wei-tmp.wei/2);dui1.pop();if(tmp.val)dui1.push(tmp);}for(;!dui2.empty();){tmp=dui2.top();++t2,pre2[t2]=tmp.val+pre2[t2-1];if(tot-pre2[t2]<=s)break;tmp.wei>>=1,tmp.val=tmp.tim*1ll*(tmp.wei-tmp.wei/2);dui2.pop();if(tmp.val)dui2.push(tmp);}int p=0;for(int i=t1;i>=0;--i){for(;tot-pre1[i]-pre2[p]>s&&p<=t2;++p);if(tot-pre1[i]-pre2[p]<=s)ans=min(ans,i+p*2);}printf("%d\n",ans);
}
int main()
{scanf("%d",&t);for(int i=1;i<=t;++i)in(),ac(),re();
}
#include<bits/stdc++.h>
#define L long long
using namespace std;
const int M=1e5+5;
struct sd{int to,wei,cst;};
struct edg{int tim,wei;L val;bool operator <(const edg &x)const{return x.val>val;}
};
int t,n,ans;
L tot,s;
vector<sd>mmp[M];
priority_queue<edg>dui1;
priority_queue<edg>dui2;
bool vis[M];
void re()
{ans=tot=0;for(int i=1;i<=n;++i)vis[i]=0;for(int i=1;i<=n;++i)mmp[i].erase(mmp[i].begin(),mmp[i].end());for(;!dui1.empty();dui1.pop());for(;!dui2.empty();dui2.pop());
}
void in()
{int a,b,c,d;scanf("%d%I64d",&n,&s);for(int i=1;i<n;++i){scanf("%d%d%d%d",&a,&b,&c,&d);mmp[a].push_back((sd){b,c,d});mmp[b].push_back((sd){a,c,d});}
}
int dfs(int v)
{L tmp,re=0;int to,wei;edg add;vis[v]=1;if(mmp[v].size()==1&&v!=1)return 1;for(int i=mmp[v].size()-1;i>=0;--i){if(vis[mmp[v][i].to])continue;to=mmp[v][i].to,wei=mmp[v][i].wei;tmp=dfs(to);add.tim=tmp,add.wei=wei,add.val=tmp*(wei-wei/2);mmp[v][i].cst==1?dui1.push(add):dui2.push(add);tot+=tmp*wei;re+=tmp;}return re;
}
void div(edg &x,int a)
{//  printf("edg:%d %d %I64d %d\n",x.tim,x.wei,x.val,a);tot-=x.val,ans+=a,x.wei>>=1,x.val=x.tim*1ll*(x.wei-x.wei/2);
}
void ac()
{dfs(1);L val,last=s+1;int flag;//return;for(edg tmp11,tmp12,tmp2;tot>s;){flag=1;//   printf("tot:%I64d\n",tot);if(dui1.empty()){tmp2=dui2.top();//    tot-=tmp2.val;div(tmp2,2),dui2.pop(),dui2.push(tmp2);continue;}tmp11=dui1.top();if(tot-tmp11.val<=s){ans+=1;break;}if(dui1.size()<2&&!dui2.empty())flag=3;else if(!dui2.empty()){val=tmp11.tim*1ll*(tmp11.wei/2-tmp11.wei/2/2);dui1.pop();tmp12=dui1.top();tmp2=dui2.top();if(val>tmp12.val)flag=2;if(tmp2.val>tmp11.val+max(val,tmp12.val))flag=3;}else{dui1.pop(),div(tmp11,1),dui1.push(tmp11);continue;}//  dec=max(tmp2.val,max(val+tmp11.val,tmp12.val+tmp11.val));//  tot-=dec;//    printf("fuck\n");//   printf("????flag:%d\n",flag);if(flag==3){// printf("flag:%d\n",flag);dui1.push(tmp11),div(tmp2,2),dui2.pop(),dui2.push(tmp2);}else if(flag==2){//   printf("flag:%d\n",flag);div(tmp11,1),last=tmp11.val,div(tmp11,1),dui1.push(tmp11);}else{//  printf("flag:%d\n",flag);div(tmp11,1),div(tmp12,1),last=tmp12.val,dui1.pop(),dui1.push(tmp11),dui1.push(tmp12);}//   ans+=2;}if(tot+last<=s)--ans;printf("%d\n",ans);
}
int main()
{scanf("%d",&t);for(int i=1;i<=t;++i)in(),ac(),re();
}

CF1399E2 Weights Division (hard version)相关推荐

  1. CodeForces - 1497E2 Square-free division (hard version)(dp+数论)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的数列,现在最多可以修改 kkk 个数字为任意数值,现在问最少可以将数列划分成多少个连续的数列,使得每一个单独的段中,任意两个数的乘积都不能是完全 ...

  2. CF1497E2 Square-free division (hard version)

    CF1497E2 Square-free division (hard version) 题意: 数组 a 由 n 个正整数构成.你需要将它们分割成最小数量的连续子段,使得每一个子段中的任意两个数(不 ...

  3. CF1497E1 Square-free division (easy version)

    CF1497E1 Square-free division (easy version) 题意: 这是简单版,此题中 k=0 给出一串长为 n 的序列 a1,a2,a3...ana_1,a_2,a_3 ...

  4. E2. Square-free division (hard version) dp + 质因子分解

    传送门 文章目录 题意: 思路: 题意: 给你长度为nnn的数组,让后最多修改其中kkk个数(可以修改为任意数),让后问你分成的最少组是多少.这个组内元素是连续的且不存在任意两个数的积为平方数. 思路 ...

  5. Codeforces Round #661 (Div. 3)题解

    目录 A.Remove Smallest(模拟) B.Gifts Fixing(模拟) C.Boats Competition(暴力枚举) D.Binary String To Subsequence ...

  6. Codeforces Round #661 (Div. 3)

    A - Remove Smallest 排个序,如果相邻的数大于一就不满足题意 #define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) ...

  7. codeforces1497 E. Square-free division(数学+dp)

    开学了,感觉没时间打cf了,上课听不懂,而且一直在忙转班的事情~~ 下周就要回学校了开心 昨天卡C题太久了,一直在想lcm的性质,还好最后回头了,当成构造题做了,瞎搞了搞就出来了,然后看D,由于没有看 ...

  8. Codeforces数学1600day3[数学CodeForces - 1213D2, CodeForces - 1165E 数论,CodeForces - 1165D 因子分解]

    ps:day2太水了不写qwq A - Equalizing by Division (hard version) CodeForces - 1213D2 题目大意:给你n个数和一个k,然后你可以执行 ...

  9. Codeforces Round #708 (Div. 2)

    Codeforces Round #708 (Div. 2) 题号 题目 知识点 A Meximization 思维 B M-arrays 思维 C1 k-LCM (easy version) 构造 ...

  10. 读文献——《Learning representations by back-propagating errors》

    Back-procedure, the procedure repeatedly adjusts the weights of the connections in the network so as ...

最新文章

  1. PyTorch训练加速17种技巧
  2. 实时大数据开发难、运维难、应用难?来,一站解决!
  3. python基础——字典
  4. VTK:创建一棵树并标记顶点和边用法实战
  5. 使用LinkedBlockingQueue来实现生产者消费者的例子
  6. arcore之路-unity开发从入门到实践_Unity游戏开发——单例模式的最佳实践
  7. UVa 1292 - Strategic game
  8. Excel 技巧大全之 01 如何将公式应用于 Excel 中的整列(5 种简单方法)
  9. 使用python判断素数
  10. 再见了飞信,再见了青春
  11. 小米小方摄像头云存储_小米摄像头离线?
  12. [BZOJ1513]Tet-Tetris 3D
  13. 电脑硬盘分区不见了怎么恢复数据?方法来啦
  14. 隐枚举法matlab程序,隐枚举法例题
  15. HTML 用过渡跟动画制作一个简易的旋转魔方
  16. POJ 3107 Godfather 笔记
  17. 主题演讲:未来新趋势电动车
  18. mac os 关闭sip保护有什么好处?有什么坏处?macOS为什么关闭sip?
  19. Arduino基础与进阶
  20. Window对象(1)

热门文章

  1. POJ1321-Chess Problem(dfs基础题)
  2. 易语言锐浪报表连接mysql_学习锐浪报表之MySQL连接字符串的实际操作步骤汇总...
  3. 简单的@Async使用 自定义连接池
  4. 向上转型---父类引用指向子类对象 A a = New B()的使用
  5. Apache VirtualHost的配置
  6. 密码键盘介绍三:数据加解密
  7. iOS Block(一)
  8. 滴滴再曝收费不靠谱:去程19元 回时164.8元
  9. USE_DB_RECOVERY_FILE_DEST的使用详解(转载)
  10. mysql 清理relay日志_Mysql 删除从数据库的relay logs最佳方式、最安全方式