Empty Triangles
Description
给出第一象限上的 M M 个固定点,接着给出次询问,每次询问四个整数 (x1,y1,x2,y2) ( x 1 , y 1 , x 2 , y 2 ) 表示询问以 (0,0),(x1,y1),(x2,y2) ( 0 , 0 ) , ( x 1 , y 1 ) , ( x 2 , y 2 ) 为顶点的三角形内是否有固定点。
Data Constraints
0≤x1,y1,x2,y2≤109
0
≤
x
1
,
y
1
,
x
2
,
y
2
≤
10
9
M,K≤105
M
,
K
≤
10
5
保证所有固定点不会在任何三角形的边界上。
Solution
将所有的固定点按照极角序排序。
考虑用线段树维护向左下角偏的凸壳,线段树区间
[l,r]
[
l
,
r
]
维护编号为
l r
l
r
的固定点组成的向左下角偏的凸壳,显然
[l,r]
[
l
,
r
]
的凸壳可以
O(r−l+1)
O
(
r
−
l
+
1
)
线性得到。
接着用二分求出夹在向量
(x1,y1)
(
x
1
,
y
1
)
和向量
(x2,y2)
(
x
2
,
y
2
)
之间的固定点的区间,接着在
log(n)
l
o
g
(
n
)
个凸壳上二分出那个最优的点,再看看是否在直线下面即可。
Code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,j,l) for(int i=j;i<=l;++i)
#define fd(i,j,l) for(int i=j;i>=l;--i)
using namespace std;
typedef long long ll;
const ll N=22e4,M=N<<2,K=M*20;
ll x[N],y[N],a[K],b[K];
int be[M],en[M],bh[N];
ll xx[K],yy[K];
ll d[M][2],e[M][2];
int n,q,ok,p;
ll a1,b1,a2,b2;
bool kmp(int x,int y)
{return (a[x]*a[y]==0)?(a[x]!=a[y]?(a[x]<a[y]):b[x]>b[y]):(b[x]*b[y]==0)?(b[x]!=b[y]?(b[x]>b[y]):a[x]<a[y]):(b[x]*a[y]>b[y]*a[x]);}
inline bool judge1(int x,int y)
{return (a[x]*a[y]==0)?(a[x]!=a[y]?(a[x]<a[y]):b[x]>b[y]):(b[x]*b[y]==0)?(b[x]!=b[y]?(b[x]>b[y]):a[x]<a[y]):(b[x]*a[y]>b[y]*a[x]);}
inline ll cj(ll x1,ll y1,ll x2,ll y2)
{return x1*y2-y1*x2;}
inline bool judge2(ll x,ll y)
{return cj(a2-a1,b2-b1,x-a1,y-b1)<0;}
inline void build(int o,int l,int r)
{
if(l==r){
be[o]=en[o]=++p;
a[p]=x[l]; b[p]=y[l];
return;
}
int mid=l+r>>1;
build(o<<1,l,mid); build((o<<1)^1,mid+1,r);
int i=be[o<<1],j=be[(o<<1)^1],ii=en[o<<1],jj=en[(o<<1)^1],v=0;
while(i<=ii||j<=jj)if(j>jj||kmp(i,j)&&i<=ii){
d[++v][0]=a[i];
d[v][1]=b[i]; ++i;
}else{
d[++v][0]=a[j];
d[v][1]=b[j]; ++j;
}
int u=0;
fo(i,1,v){
ll r1=d[i][0],r2=d[i][1];
while(u>1&&cj(r1-e[u-1][0],r2-e[u-1][1],e[u][0]-e[u-1][0],e[u][1]-e[u-1][1])>=0)
--u;
e[++u][0]=r1; e[u][1]=r2;
}
be[o]=p+1; en[o]=p+u;
fo(i,1,u)a[i+p]=e[i][0],b[i+p]=e[i][1];
p=en[o];
}
inline void find(int o,int l,int r,int le,int ri)
{
if(l==le&&r==ri){
if(be[o]+1>=en[o])fo(i,be[o],en[o])ok=ok|(judge2(a[i],b[i]));
else{
int zb=be[o],yb=en[o];
ok=ok|judge2(a[zb],b[zb]);
ok=ok|judge2(a[yb],b[yb]);
++zb;
while(zb+1<yb){
int mid=zb+yb>>1;
ll d1=cj(a2-a1,b2-b1,a[mid]-a[mid-1],b[mid]-b[mid-1]);
ll d2=cj(a2-a1,b2-b1,a[mid+1]-a[mid],b[mid+1]-b[mid]);
if((d2>0)&&d1>=0)yb=mid;else zb=mid;
}
ok=ok|judge2(a[zb],b[zb]);
}
return;
}
int mid=l+r>>1;
if(ri<=mid)find(o<<1,l,mid,le,ri);
else if(le>mid)find((o<<1)^1,mid+1,r,le,ri);
else{
find(o<<1,l,mid,le,mid);
if(ok)return;
find((o<<1)^1,mid+1,r,mid+1,ri);
}
}
int main()
{
scanf("%d%d",&n,&q);
fo(i,1,n)scanf("%lld%lld",&a[i],&b[i]);
fo(i,1,n)bh[i]=i;
sort(bh+1,bh+n+1,kmp);
fo(i,1,n)x[i]=a[bh[i]],y[i]=b[bh[i]];
build(1,1,n);
fo(i,1,q){
scanf("%lld%lld%lld%lld",&a1,&b1,&a2,&b2);
if(b1*a2<a1*b2||b1==0)swap(a1,a2),swap(b1,b2);
int l1=0,r1=n+1;
while(l1+1<r1){
int mid=l1+r1>>1;
if(b1*x[mid]>=a1*y[mid])r1=mid;else l1=mid;
}
int l2=0,r2=n+1;
while(l2+1<r2){
int mid=l2+r2>>1;
if(y[mid]*a2>=x[mid]*b2)l2=mid;else r2=mid;
}
if(r1>l2)puts("N");
else{
ok=judge2(x[l2],y[l2]);
find(1,1,n,r1,l2);
if(ok)puts("Y");else puts("N");
}
}
return 0;
}