#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<list>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define memset(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define MAXM 200100 //1e5+10 为何不可
using namespace std;
ll K;
int n;
ll a[MAXM];//!!因为b[i]=k/a[i]
ll b[MAXM];
int access[MAXM];
int total;
ll ans;
int head[MAXM];
int number[MAXM<<3];
int m;//线段树,离散化后,最大长度
struct EDGE{
int v;//到达点
int last;//同一点出发的上一条边,初始边是-1
}Edge[MAXM];
void Add(int u,int v){
Edge[total].v=v;
Edge[total].last=head[u];
head[u]=total++;
}
/*
void Build(int root,int l,int r){
if(l==r){
number[root]=0;
return ;
}
int mid=(l+r)/2;
int subroot_l=root<<1;
int subroot_r=subroot_l+1;
Build(subroot_l,l,mid);
Build(subroot_r,mid+1,r);
number[root]=number[subroot_l]+number[subroot_r];
return;
}
*/
int Query(int root,int l,int r,int x,int y){
if(l==x&&r==y){//l>=x&&r<=y
return number[root];
}
int mid=(l+r)/2;
int subroot_l=root<<1;
int subroot_r=subroot_l+1;
if(y<=mid){
return Query(subroot_l,l,mid,x,y);
}
else if(x>=mid+1){
return Query(subroot_r,mid+1,r,x,y);
}
else{
return Query(subroot_l,l,mid,x,mid)+Query(subroot_r,mid+1,r,mid+1,y);
}
}
void Update(int root,int l,int r,int pos_update,int value_update){
if(l==r){//不能写成l==pos_update或者r==pos_update
number[root]+=value_update;
return ;
}
int mid=(l+r)/2;
int subroot_l=root<<1;
int subroot_r=subroot_l+1;
if(pos_update<=mid){
Update(subroot_l,l,mid,pos_update,value_update);
}
else if(mid+1<=pos_update){
Update(subroot_r,mid+1,r,pos_update,value_update);
}
number[root]=number[subroot_l]+number[subroot_r];//这一句不要忘记写!!递归往上回溯,不断更新每一层的各个区间。
}
void Dfs(int u){
int pos_query=lower_bound(b+1,b+m+1,K/a[u])-b;/// -b,还是-(b+1)
int pos_update=lower_bound(b+1,b+m+1,a[u])-b;
ans+=1ll*Query(1,1,m,1,pos_query);//区间查询,所以传递的查询参数除了整个查询开始的范围(1,1,m)/* 如果建立的线段树不是像本题一样是个数组,而是节点node,每个节点有left,right,value,那么只需要1这个开始的节点的id即可,而本题这样的数组只存线段树每个节点的value那么就需要存储l、r每到一层都算一次*/,再加上查询区间的左边界(1)和右边界(pos_query)
Update(1,1,m,pos_update,1);//单点更新,所以参数传递除了整个查询开始的范围,只需要更改点的位置(pos_update)以及更改数值(1)即可。
for(int i=head[u];i!=-1;i=Edge[i].last) Dfs(Edge[i].v);
Update(1,1,m,pos_update,-1);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
total=ans=0;
memset(access,0);
memset(head,-1);//Edge不用memset,只要head和total初始化即可
scanf("%d%I64d",&n,&K);
for(int i=1;i<=n;i++){
scanf("%I64d",&a[i]);
b[i]=a[i];
b[i+n]=K/a[i];
}
sort(b+1,b+1+2*n);//排序,离散化的基础
m=unique(b+1,b+1+2*n)-(b+1);/// -b,还是-(b+1)
//线段树的叶子(点)个数
int u,v;
//Build(1,1,m);// 没什么意义,因为建立的空的线段树,随后按题目中构造的树,从根部出发DFS顺序遍历,不断往线段树上加点和删点;
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
Add(u,v);
access[v]++;
}
for(int i=1;i<=n;i++){
if(access[i]==0) Dfs(i);
}
cout<<ans<<endl;
}
}