test 2 最后一个询问的答案是 918957089641524701,我的答案是 918957089641524619。
我的思路就是每个靶子的左右端点分开讨论,归类到负斜率和正斜率。假设有 posc 个正斜率,negc 个负斜率。右上端点对应负斜率,右下端点对应正斜率,各自恰好有 n 个点。左边的端点按 y 值从小到大排序,下方的 posc−n 个归负斜率,上方的 neg−n 个归正斜率。
考虑到答案即为负斜率对应点的最大值减去正斜率对应点的最小值,因此对正负斜率分别二分即可。
check(t) 的规则是:对于正斜率,枚举每个 (x,y),所有满足 s≤⌊xy−t⌋ 的 s 都能使得过 (x,y) 的斜率为 s 的直线经过 y 轴上的点 y0 满足 y0≥t;对于负斜率,枚举每个 (x,y),所有满足 s≥⌊xy−t⌋ 的 s 都能使得过 (x,y) 的斜率为 s 的直线经过 y 轴上的点 y0 满足 y0≤t。
findpos(x) 是找到正斜率中最后一个满足 s≤x 的位置;findneg(x) 是找到负斜率中第一个满足 s≥x 的位置。正负斜率都从小到大排序。
以下是代码
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
inline ll read(){
ll x=0;
int f=0,ch=0;
while(ch<48||ch>57) f=(ch=='-'),ch=getchar();
while(ch>47&&ch<58) x=(x<<3)+(x<<1)+(ch&15),ch=getchar();
return f?-x:x;
}
inline void write(ll x,char end='\n'){
if(x==0){
putchar('0');
putchar(end);
return;
}
if(x<0) putchar('-'),x=-x;
int ch[40]={0},cnt=0;
while(x){
ch[cnt++]=(int)(x%10);
x/=10;
}
while(cnt--) putchar(ch[cnt]+48);
putchar(end);
}
const ll inf=4e18;
const int N=2e5+5;
int n,x1;
struct node{
ll x,y;
}pos[N],neg[N],left[N];
inline bool cmp(node x,node y){
return x.y<y.y;
}
int poscnt,negcnt,cnt;
int pcnt,ncnt;
ll posc[N],negc[N];
ll s[N];
inline ll getceil(ll x,ll y){return ceil(x*1.0/y);}
inline ll getfloor(ll x,ll y){return floor(x*1.0/y);}
inline int findneg(ll x){
if(negc[ncnt]<x) return ncnt+1;
int l=1,r=ncnt;
while(l<r){
int mid=(l+r)>>1;
if(negc[mid]>=x) r=mid;
else l=mid+1;
}
return l;
}
inline int findpos(ll x){
if(posc[1]>x) return 0;
int l=1,r=pcnt;
while(l<r){
int mid=(l+r+1)>>1;
if(posc[mid]<=x) l=mid;
else r=mid-1;
}
return l;
}
int sumneg[N<<1],sumpos[N<<1];
inline bool checkneg(ll t){
for(int i=1;i<=ncnt+1;++i) sumneg[i]=0;
for(int i=1;i<=ncnt;++i){
ll x=neg[i].x,y=neg[i].y;
ll g=getceil(y-t,x);
int p=findneg(g);
sumneg[p]++;
}
for(int i=1;i<=ncnt;++i){
sumneg[i]+=sumneg[i-1];
if(sumneg[i]<i) return 0;
}
// printf("successful: %lld\n",t);
return 1;
}
inline bool checkpos(ll t){
for(int i=1;i<=pcnt+1;++i) sumpos[i]=0;
for(int i=1;i<=poscnt;++i){
ll x=pos[i].x,y=pos[i].y;
ll g=getfloor(y-t,x);
int p=findpos(g);
sumpos[p]++;
}
for(int i=pcnt;i>=1;--i){
sumpos[i]+=sumpos[i+1];
if(sumpos[i]<pcnt-i+1) return 0;
}
// printf("successful: %lld\n",t);
return 1;
}
int main(){
// freopen("P10190_2.in","r",stdin);
int T=read();
while(T--){
n=read(),x1=read();
poscnt=negcnt=0;
cnt=0;
for(int i=1;i<=n;++i){
ll y1=read(),y2=read(),x2=read();
pos[++poscnt]={x2,y1};
neg[++negcnt]={x2,y2};
left[++cnt]={x1,y1};
left[++cnt]={x1,y2};
}
pcnt=0,ncnt=0;
for(int i=1;i<=n*4;++i){
s[i]=read();
if(s[i]>0)
posc[++pcnt]=s[i];
if(s[i]<0)
negc[++ncnt]=s[i];
}
if(pcnt<n){
puts("-1");
continue;
}
if(ncnt<n){
puts("-1");
continue;
}
sort(posc+1,posc+pcnt+1);
sort(negc+1,negc+ncnt+1);
sort(left+1,left+cnt+1,cmp);
int gg=pcnt-poscnt;
for(int i=1;i<=gg;++i) pos[++poscnt]=left[i];
for(int i=gg+1;i<=cnt;++i) neg[++negcnt]=left[i];
ll l=1,r=inf;
while(l<r){
ll mid=(l+r)>>1;
if(checkneg(mid)) r=mid;
else l=mid+1;
}
ll up=l;
l=-inf,r=-1;
while(l<r){
ll mid=(l+r+1)>>1;
if(checkpos(mid)) l=mid;
else r=mid-1;
}
ll down=l;
write(up-down);
}
return 0;
}