#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5,M=3e6,INF=0x3fffffff;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N],cnt1,cnt2;
long long s,f1[M],f2[M],ans;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline long long divide(int i)
{
	long long res=val(i);
	len[i]/=2;
	return res;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		s=-s;
		F(i,0,n)s+=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		ans=INF;
		cnt1=cnt2=0;
		f1[0]=f2[0]=0;
		while(!q1.empty())
		{
			int a=q1.top();q1.pop();
			f1[cnt1+1]=divide(a)+f1[cnt1];
			++cnt1;
			if(len[a])q1.push(a);
		}
		while(!q2.empty())
		{
			int a=q2.top();q2.pop();
			f2[cnt2+1]=divide(a)+f2[cnt2];
			++cnt2;
			if(len[a])q2.push(a);
		}
		for(int i=0,j=cnt1;i<=cnt2;++i)
		{
			while(j&&f2[i]+f1[j-1]>=s)--j;
			if(f2[i]+f1[j]>=s)if(ans>2*i+j)ans=2*i+j;
		}
		printf("%d\n",ans);
	}
	return 0;
}


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const
	{return (long long)div(len[a])*siz[a]<(long long)div(len[b])*siz[b];}
};
priority_queue<int,vector<int>,cmp> q;
void adline(int u,int v,int w)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w;read(u);read(v);read(w);
			adline(--u,--v,w);adline(v,u,w);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q.empty())q.pop();
		F(i,0,n)q.push(i);
		while(s<0&&!q.empty())
		{
			int i=q.top();q.pop();
			++ans;
			s+=(long long)div(len[i])*siz[i];
			len[i]/=2;
			if(len[i])q.push(i);
		}
		printf("%d\n",ans);
	}
	return 0;
}


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*len[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=(long long)div(len[i])*siz[i];
	len[i]/=2;
	if(len[i])(cost[i]==1?q1:q2).push(i);
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,0,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top(),bb=div(a/2)*len[a];q1.pop();
				int c=q2.top();q2.pop();
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*len[a];
				int c=q2.top();q2.pop();
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define int long long
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
signed main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top(),bb=div(a/2)*siz[a];q1.pop();
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top(),bb=div(a/2)*siz[a];q1.pop();
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define int long long
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
signed main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top(),bb=div(a/2)*siz[a];q1.pop();
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%lld\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()//zkyAKIOI
{
	read(T);//zhouAKngyang
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top(),bb=div(a/2)*siz[a];q1.pop();
				int c=q2.top();q2.pop();
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
5 50
1 3 100 1
1 5 10 2
2 3 123 2
5 4 55 1
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>=val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=(long long)div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(s+val(c)>=0){ans+=2;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include<cstdio>
#include<queue>
#define F(i,l,r) for(int i=l,i##_end=r;i<i##_end;++i)
#define div(a) ((a)-(a)/2)
#define val(a) ((long long)div(len[a])*siz[a])
using namespace std;
const int N=1e5+5;
template<typename T>void read(T &x)
{
	bool neg=false;
	unsigned char c=getchar();
	for(;(c^48)>9;c=getchar())if(c=='-')neg=true;
	for(x=0;(c^48)<10;c=getchar())x=(x<<3)+(x<<1)+(c^48);
	if(neg)x=-x;
}
struct line
{
	int next,to,dis,cost;
}e[2*N];
int T,n,hd[N],cnt,siz[N],len[N],cost[N];
long long s;
struct cmp
{
	bool operator()(int a,int b)const{return val(a)<val(b);}
};
priority_queue<int,vector<int>,cmp> q1,q2;
void adline(int u,int v,int w,int c)
{
	e[cnt].to=v;
	e[cnt].dis=w;
	e[cnt].cost=c;
	e[cnt].next=hd[u];
	hd[u]=cnt++;
}
void dfs(int u,int fa)
{
	siz[u]=0;
	for(int i=hd[u];~i;i=e[i].next)
	{
		int v=e[i].to;
		if(v==fa)continue;
		len[v]=e[i].dis;
		cost[v]=e[i].cost;
		dfs(v,u);
		siz[u]+=siz[v];
	}
	if(!siz[u])siz[u]=1;
}
inline void divide(int i)
{
	s+=val(i);
	len[i]/=2;
}
int main()
{
	read(T);
	while(T--)
	{
		int ans=0;
		read(n);read(s);
		F(i,0,n)hd[i]=-1;
		cnt=0;
		F(i,0,n-1)
		{
			int u,v,w,c;read(u);read(v);read(w);read(c);
			adline(--u,--v,w,c);adline(v,u,w,c);
		}
		dfs(0,0);
		F(i,0,n)s-=(long long)len[i]*siz[i];
		while(!q1.empty())q1.pop();
		while(!q2.empty())q2.pop();
		F(i,1,n)if(cost[i]==1)q1.push(i);else q2.push(i);
		while(s<0&&(q1.size()+q2.size()))
		{
			if(q1.size()>1&&q2.size()>0)
			{
				int a=q1.top();q1.pop();
				int b=q1.top();q1.pop();
				long long bb=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+(val(b)>bb?val(b):bb)>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
				q1.push(b);
			}
			else if(q2.size()==0)
			{
				int a=q1.top();q1.pop();
				++ans;
				divide(a);
				if(len[a])q1.push(a);
			}
			else if(q1.size()==0)
			{
				int c=q2.top();q2.pop();
				ans+=2;
				divide(c);
				if(len[c])q2.push(c);
			}
			else
			{
				int a=q1.top();q1.pop();
				long long b=div(a/2)*siz[a];
				int c=q2.top();q2.pop();
				if(s+val(a)>=0){++ans;break;}
				if(val(a)+b>val(c))
				{
					++ans;
					divide(a);
				}
				else
				{
					ans+=2;
					divide(c);
				}
				if(len[a])q1.push(a);
				if(len[c])q2.push(c);
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}
/*
1
10 22
6 5 1 1
3 2 5 1
10 8 4 1
8 7 6 2
7 6 6 1
9 8 9 1
5 3 3 1
2 1 7 1
4 3 9 2
*/


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<LL> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (t.fi - t.fi/2) * t.se;
            v1.push_back(sum1) ;

            heap1.push({t.fi/2 , t.se}) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (t.fi - t.fi/2) * t.se;
            v2.push_back(sum2) ;

            heap2.push({t.fi/2 , t.se}) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        //for(int i = 0 ; i < a ; ++ i )  cout << v1[i] << ' ' ; cout << endl;
        //for(int i = 0 ; i < b ; ++ i )  cout << v2[i] << ' ' ; cout << endl;
        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int k = m - v1[i] ;
            int j = (int)(upper_bound(v2.begin() , v2.end() , k , greater<int>()) - v2.begin()) ;
            //cout << i << ' ' << j << ' ' << k << endl;
            if(j-1 >= 0 && v1[i] + v2[j-1] <= m)
                cnt = min(cnt , i + (j-1) * 2) ;
            if(v1[i] + v2[j-1] <= m)
                cnt = min(cnt , i + j * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<int> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        //for(int i = 0 ; i < a ; ++i)    cout << v1[i] << ' ' ; cout << endl;
        //for(int i = 0 ; i < b ; ++i)    cout << v2[i] << ' ' ; cout << endl;
        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] >= k) r = mid ;
                else    l = mid + 1 ;
            }

            if(v1[i] + v2[l] <= m)
                cnt = min(cnt , i + l * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<int> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(heap1.size()){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (t.fi - t.fi/2) * t.se;
            if(t.fi/2)
                heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(heap2.size()){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (t.fi - t.fi/2) * t.se;
            if(t.fi/2)
                heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        //for(int i = 0 ; i < a ; ++i)    cout << v1[i] << ' ' ; cout << endl;
        //for(int i = 0 ; i < b ; ++i)    cout << v2[i] << ' ' ; cout << endl;
        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[l] <= m)
                cnt = min(cnt , i + l * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<int> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        //for(int i = 0 ; i < a ; ++i)    cout << v1[i] << ' ' ; cout << endl;
        //for(int i = 0 ; i < b ; ++i)    cout << v2[i] << ' ' ; cout << endl;
        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] > k) l = mid + 1 ;
                else    r = mid ;
            }

            if(v1[i] + v2[l] <= m)
                cnt = min(cnt , i + l * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<LL> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (LL)(t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (LL)(t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[r] <= m)
                cnt = min(cnt , i + (LL)r * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<int> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (LL)(t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (LL)(t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[l] <= m)
                cnt = min(cnt , i + l * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<int> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (LL)(t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (LL)(t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[r] <= m)
                cnt = min(cnt , i + r * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<LL> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (LL)(t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (LL)(t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            LL k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[r] <= m)
                cnt = min(cnt , i + r * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            sum += (LL)w[i] * son[j] ;
            if(cost[i] == 1)
                heap1.push({w[i] , son[j]}) ;
            else
                heap2.push({w[i] , son[j]}) ;

            dfs2(j , u , heap1 , heap2 , sum) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum) ;

        int cnt = 0 ;

        while(sum > m)
        {
            PII t1 = {0,0}, t2 = {0,0} ;
            if(heap1.size())
            {
                t1 = heap1.top() ;
                heap1.pop() ;
            }

            if(heap2.size())
            {
                t2 = heap2.top() ;
                heap2.pop() ;
            }

            LL x1 = (LL)(t1.fi - t1.fi/2) * t1.se ;
            LL x2 = (LL)(t2.fi - t2.fi/2) * t2.se ;

            if(sum - x1 > m && sum - x2 > m)
            {
                double temp = x2 / 2.0 ;
                if(x1 > temp){  //选第一个
                    cnt ++ ;
                    sum -= x1 ;
                    heap1.push({t1.fi/2 , t1.se}) ;
                    heap2.push(t2) ;
                }else{
                    cnt += 2;
                    sum -= x2 ;
                    heap2.push({t2.fi/2 , t2.se}) ;
                    heap1.push(t1) ;
                }
            }else{
                if(sum - x1 <= m){
                    sum -= x1 ;
                    cnt ++ ;

                }else if(sum - x2 <= m){
                    sum -= x2 ;
                    cnt += 2 ;

                }
            }

        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<LL> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (t.fi - t.fi/2) * t.se;
            v1.push_back(sum1) ;

            heap1.push({t.fi/2 , t.se}) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (t.fi - t.fi/2) * t.se;
            v2.push_back(sum2) ;

            heap2.push({t.fi/2 , t.se}) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        //for(int i = 0 ; i < a ; ++ i )  cout << v1[i] << ' ' ; cout << endl;
        //for(int i = 0 ; i < b ; ++ i )  cout << v2[i] << ' ' ; cout << endl;
        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int k = m - v1[i] ;
            int j = (int)(upper_bound(v2.begin() , v2.end() , k , greater<int>()) - v2.begin()) ;
            //cout << i << ' ' << j << ' ' << k << endl;
            if(j-1 >= 0 && v1[i] + v2[j-1] <= m)
                cnt = min(cnt , i + (j-1) * 2) ;
            if(v1[i] + v2[j] <= m)
                cnt = min(cnt , i + j * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}


#include <iostream>
#include <cstring>
#include <map>
#include <vector>
#include <queue>
#include <algorithm>

#define fi first
#define se second

using namespace std ;

const int N = 1e5+10 , M = 2*N;

typedef long long LL ;
typedef pair<int,int> PII ;

int n ;
LL m ;

int h[N] , e[M] , w[M] , cost[M] , ne[M] , idx ;
void add(int a , int b , int c , int d)
{
    e[idx] = b , w[idx] = c , cost[idx] = d , ne[idx] = h[a] , h[a] = idx++ ;
}

int fa[N] , son[N] ;    //fa[1] = 0
vector<int> leaf ;   //标记叶子节点

int dfs(int u , int pa)
{
    son[u] = 0 ;
    for(int i = h[u] ; ~i ; i = ne[i] )
    {
        int j = e[i] ;
        if(j != pa)
        {
            fa[j] = u ;
            son[u] += dfs(j , u) ;
        }
    }

    if(son[u] == 0)
    {
        leaf.push_back(u) ;
        son[u] = 1;
    }

    return son[u];
}

struct cmp{ //大根堆
    bool operator()(PII &a , PII &b)    //每次挑选变化量最大
    {
        return (LL)(a.fi-a.fi/2)*a.se < (LL)(b.fi-b.fi/2)*b.se ;
    }
};

void dfs2(int u , int fa , priority_queue<PII , vector<PII> , cmp> &heap1 ,
                           priority_queue<PII , vector<PII> , cmp> &heap2 ,LL &sum1 , LL &sum2)
{
    for(int i = h[u] ; ~i ; i = ne[i])
    {
        int j = e[i] ;
        if(j != fa)
        {
            if(cost[i] == 1){
                heap1.push({w[i] , son[j]}) ;
                sum1 += (LL)w[i] * son[j] ;
            }else{
                heap2.push({w[i] , son[j]}) ;
                sum2 += (LL)w[i] * son[j] ;
            }
            dfs2(j , u , heap1 , heap2 , sum1 , sum2) ;
        }
    }
}

int main()
{
    int T ;
    scanf("%d" , &T) ;
    while( T -- )
    {
        cin >> n >> m ;

        memset(h , -1 , sizeof h) ;
        memset(fa , 0 , sizeof fa) ;
        memset(son , 0 , sizeof son) ;

        idx = 0 ;
        leaf.clear() ;

        for(int i = 0 ; i < n-1 ; ++i)
        {
            int a , b , c , d;
            scanf("%d%d%d%d" , &a , &b , &c , &d) ;
            add(a , b , c , d ) ;
            add(b , a , c , d ) ;

        }

        dfs(1 , 0) ; //找到所有叶子节点

        priority_queue<PII , vector<PII> , cmp>   heap1 , heap2 ;
        LL sum1 = 0 , sum2 = 0 ;    //总权重

        dfs2(1 , 0 , heap1 , heap2 ,  sum1 , sum2) ;

        vector<LL> v1 , v2 ;

        v1.push_back(sum1) ;
        v2.push_back(sum2) ;

        while(sum1){
            auto t = heap1.top() ;
            heap1.pop() ;
            sum1 -= (LL)(t.fi - t.fi/2) * t.se;
            heap1.push({t.fi/2 , t.se}) ;
            v1.push_back(sum1) ;
        }

        while(sum2){
            auto t = heap2.top() ;
            heap2.pop() ;
            sum2 -= (LL)(t.fi - t.fi/2) * t.se;
            heap2.push({t.fi/2 , t.se}) ;
            v2.push_back(sum2) ;
        }

        int cnt = 0x3f3f3f3f ;
        int a = v1.size() , b = v2.size() ;

        for(int i = 0 ; i < a ; ++i)
        {
            //找到小于等于s-v1[i]的最大值所在的下标
            int l = 0 , r = b-1 ;
            int k = m - v1[i] ;
            while(l < r){
                int mid = l+r >> 1 ;
                if(v2[mid] <= k) r = mid ;
                else    l = mid+1 ;
            }

            if(v1[i] + v2[r] <= m)
                cnt = min(cnt , i + r * 2) ;
        }

        cout << cnt << endl;

    }

    return 0;
}