如题,用二分确定左右端点
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define double long double
inline ll read()
{
ll s=0,w=1;
char c=getchar();
while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
while(c>='0'&&c<='9'){s=s*10+(c-'0'),c=getchar();}
return s*w;
}
inline void out(ll x)
{
ll w=x,c[10005],len=0;
if(w<0) putchar('-'),w=-w;
if(w==0){putchar('0');return;}
while(w) len++,c[len]=w%10+'0',w/=10;
while(len) putchar(c[len]),len--;
}
const ll M=1e5+5,N=1e9+5;
ll t,n,m,L,V,d[M],v[M],a[M],p[M];
ll cnt,del[M],ans;
struct node
{
ll l,r;
}b[M];
bool cmp(node x,node y)
{
return (x.l==y.l?x.r>y.r:x.l<y.l);
}
int main()
{
t=read();
while(t--)
{
cnt=0;
n=read(),m=read(),L=read(),V=read();
for(int i=1;i<=n;i++)
{
d[i]=read(),v[i]=read(),a[i]=read();
}
for(int i=1;i<=m;i++)
{
p[i]=read();
}
for(int i=1;i<=n;i++)
{
if(v[i]<=V&&a[i]<=0) continue;
if(a[i]>0)
{
ll s;
if(v[i]>V) s=d[i]-1;
else s=(V*V-v[i]*v[i])/2/a[i]+d[i];
ll l=1,r=m,ans=0,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(p[mid]>s)
{
r=mid-1;
ans=mid;
}
else l=mid+1;
}
if(ans)
{
b[++cnt].l=ans,b[cnt].r=L;
//cout<<d[i]<<" "<<v[i]<<a[i]<<endl;
//cout<<ans<<" "<<L<<endl<<endl;
}
}
else
{
ll l=1,r=m,ans1=0,mid,ans2=0;
while(l<=r)
{
mid=(l+r)>>1;
if(p[mid]>=d[i])
{
r=mid-1;
ans1=mid;
}
else l=mid+1;
}
if(!ans1) continue;
l=ans1,r=m;
while(l<=r)
{
mid=(l+r)/2;
double s=sqrt(v[i]*v[i]*1.0+2.0*a[i]*(p[mid]-d[i]));
if(s>V)
{
l=mid+1;
ans2=mid;
}
else r=mid-1;
}
if(ans1<=ans2)
{
b[++cnt].l=ans1,b[cnt].r=ans2;
//cout<<d[i]<<" "<<v[i]<<a[i]<<endl;
//cout<<ans<<" "<<L<<endl<<endl;
}
}
}
sort(b+1,b+1+cnt,cmp);
ll pos=N;
for(int i=cnt;i>=1;i--)
{
if(pos<=b[i].r)
{
del[i]=1;
}
pos=min(pos,b[i].r);
}
ans=0,pos=0;
for(int i=1;i<=cnt;i++)
{
if(del[i])
{
del[i]=0;
continue;
}
if(pos<b[i].l)
{
ans++,pos=b[i].r;
}
}
out(cnt),putchar(' '),out(m-ans),putchar('\n');
}
return 0;
}