#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+666,M=1e6+666;
int n,m,len,V,cnt,p[N],s[M],tmp[M],tot,anser;
bool vis[N];
struct car{
int d,v,a;
}c[N];
struct lr{
int l,r;
}st[N];
struct node{
int val,idx;
};
struct tree{
int l,r,pre,lzy,idx;
}t[N<<2];
inline void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
t[p].lzy=t[p].pre=0;
t[p].idx=l;
return;
}
int son=p<<1,mid=l+r>>1;
build(son,l,mid);
build(son|1,mid+1,r);
t[p].idx=t[son].idx;
t[p].pre=t[p].lzy=0;
return;
}
inline void spread(int p){
int son=p<<1;
if(t[p].lzy){
t[son].lzy+=t[p].lzy;
t[son].pre+=t[p].lzy;
t[son|1].lzy+=t[p].lzy;
t[son|1].pre+=t[p].lzy;
t[p].lzy=0;
}
return;
}
inline void change(int p,int l,int r,int data){
if(t[p].l>=l&&t[p].r<=r){
t[p].lzy+=data;
t[p].pre+=data;
return;
}
spread(p);
int son=p<<1,mid=t[p].l+t[p].r>>1;
if(l<=mid)
change(son,l,r,data);
if(r>mid)
change(son|1,l,r,data);
if(t[son].pre>t[son|1].pre)
t[p].idx=t[son].idx;
else
t[p].idx=t[son|1].idx;
t[p].pre=max(t[son].pre,t[son|1].pre);
return;
}
inline node ask(int p,int l,int r){
node ans=node{0,0},now;
if(t[p].l>=l&&t[p].r<=r)
return node{t[p].pre,t[p].idx};
int son=p<<1,mid=t[p].l+t[p].r>>1;
spread(p);
if(l<=mid){
now=ask(son,l,r);
if(ans.val<now.val)
ans=now;
}
if(r>mid){
now=ask(son|1,l,r);
if(ans.val<now.val)
ans=now;
}
return ans;
}
inline void check(int idx){
int d=c[idx].d,v=c[idx].v,a=c[idx].a,loc,pos;
if(a==0){
if(v>V){
loc=upper_bound(p+1,p+m+1,d)-p;
while(loc&&p[loc-1]==d)
loc--;
st[++tot]=lr{loc,m};
anser++;
}
return;
}
if(a>0){
if(v>V){
if(d<=p[m]){
loc=upper_bound(p+1,p+m+1,d)-p;
while(loc&&p[loc-1]==d)
loc--;
st[++tot]=lr{loc,m};
anser++;
}
}
else{
loc=V*V-v*v;
loc/=(a<<1);
if(d+loc<=p[m]){
pos=upper_bound(p+1,p+m+1,d+loc)-p;
while(((p[pos-1]-d)*a<<1)>V*V-v*v)
pos--;
st[++tot]=lr{pos,m};
anser++;
}
}
return;
}
if(a<0){
if(v<V){
return;
}
else{
loc=V*V-v*v;
loc/=(a*2);
int en=min(len,d+loc);
if(s[en]-s[d-1]>0){
pos=lower_bound(p+1,p+m+1,en)-p;
while(pos&&(p[pos+1]-d)*(-a)*2>=v*v-V*V)
pos--;
while(((p[pos+1]-d)*(-a)*2<v*v-V*V)&&pos<m)
pos++;
st[++tot].r=pos;
pos=upper_bound(p+1,p+m+1,d)-p;
while(pos&&p[pos-1]==d)
pos--;
st[tot].l=pos;
anser++;
}
return;
}
return;
}
return;
}
int main(){
freopen("detect.in","r",stdin);
freopen("detect.out","w",stdout);
int T,x,y,z,ll,rr,ans;
node now;
scanf("%d",&T);
while(T--){
cnt=anser=ans=tot=0;
memset(tmp,0,sizeof(tmp));
scanf("%d%d%d%d",&n,&m,&len,&V);
for(int i=1;i<=n;++i){
scanf("%d%d%d",&x,&y,&z);
c[++cnt]=car{x,y,z};
}
for(int i=1;i<=m;++i)
scanf("%d",&p[i]),tmp[p[i]]++;
sort(p+1,p+m+1);
s[0]=tmp[0];
for(int i=1;i<=len;++i)
s[i]=s[i-1]+tmp[i];
for(int i=1;i<=n;++i)
check(i);
build(1,1,m);
for(int i=1;i<=tot;++i){
ll=st[i].l,rr=st[i].r;
vis[i]=true;
change(1,ll,rr,1);
}
now=ask(1,1,m);
while(now.val!=0){
ans++;
for(int i=1;i<=tot;++i){
if(!vis[i]||now.idx>st[i].r||now.idx<st[i].l)
continue;
change(1,st[i].l,st[i].r,-1);
vis[i]=false;
}
now=ask(1,1,m);
}
printf("%d %d\n",anser,m-ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}