Description
给出一些在二维平面中第一象限的点,
有多个询问,每次给出两个点(x,y),(x1,y1),要求顶点为(0,0),(x,y),(x1,y1)的三角形内是否有点,
Solution
我们分别过点(x,y),(0,0)和(0,0),(x1,y1)作两直线,把两直线之间的点挑出来,
显然的,如果三角形内存在点,那么一定在凸包上,
那么我们维护区间凸包即可,
复杂度: O(nlog2(n)) O ( n log 2 ( n ) )
Code
#include <cstdio>
#include <algorithm>
#include <cmath>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
#define CJ1(q,w,x,y) ((LL)(w)*(x)-(LL)(q)*(y)>0)
#define CJ(q,w,x,y) (((LL)(w)*(LL)(x)-(LL)(q)*(LL)(y))>=0)
using namespace std;
typedef long long LL;
const int N=100500;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,ans;
int a1[N][2],a0[N][2];
struct VAL
{
int x,y;
}a[N];
bool PX(VAL q,VAL w){return CJ1(q.x,q.y,w.x,w.y);}
int d[N*20][2],d0,d1[N*20][2],d01;
int zx[N*4][2],zx1[N*4][2];
int CC;
void build(int l,int r,int e)
{
if(l==r)
{
zx[e][0]=zx[e][1]=++d0;
zx1[e][0]=zx1[e][1]=++d01;
d1[d01][0]=d[d0][0]=a[l].x;
d1[d01][1]=d[d0][1]=a[l].y;
return;
}
int mid=(l+r)>>1;
build(l,mid,e<<1);
build(mid+1,r,e<<1|1);
int i=l,j=mid+1,k=1;
for(;i<=mid||j<=r;++k)
{
if(j>r||(i<=mid&&(a[i].x<a[j].x||(a[i].x==a[j].x&&a[i].y<a[j].y))))
{
a1[k][0]=a[i].x,a1[k][1]=a[i].y;
++i;
}else a1[k][0]=a[j].x,a1[k][1]=a[j].y,++j;
}
zx[e][0]=d0+1;
fo(i,l,r)
{
a[i].x=a1[i-l+1][0],a[i].y=a1[i-l+1][1];
if(i>l&&a[i].x==a[i-1].x)continue;
for(;d0>zx[e][0]&&CJ(d[d0][0]-a[i].x,d[d0][1]-a[i].y,d[d0][0]-d[d0-1][0],d[d0][1]-d[d0-1][1]);--d0);
d[++d0][0]=a[i].x;
d[d0][1]=a[i].y;
}
zx[e][1]=d0;
zx1[e][0]=d01+1;
fo(i,l,r)
{
for(;d01>zx1[e][0]&&CJ(a[i].x-d1[d01][0],a[i].y-d1[d01][1],d1[d01][0]-d1[d01-1][0],d1[d01][1]-d1[d01-1][1]);--d01)
d1[++d01][0]=a[i].x;
d1[d01][1]=a[i].y;
}
zx1[e][1]=d01;
}
LL X2,Y2,X1,Y1;
bool Ks;
bool CEK(int e)
{
if(Ks)
{
int l=zx[e][0],r=zx[e][1]-1;
for(;l<r;)
{
int mid=(l+r)>>1;
if(CJ(X2-X1,Y2-Y1,d[mid+1][0]-d[mid][0],d[mid+1][1]-d[mid][1]))l=mid+1;
else r=mid;
}
return CJ(d[l][0]-X2,d[l][1]-Y2,X1-X2,Y1-Y2)||((l<=r)&&CJ(d[l+1][0]-X2,d[l+1][1]-Y2,X1-X2,Y1-Y2));
}
int l=zx1[e][0],r=zx1[e][1]-1;
for(;l<r;)
{
int mid=(l+r)>>1;
if(CJ(d1[mid+1][0]-d1[mid][0],d1[mid+1][1]-d1[mid][1],X1-X2,Y1-Y2))l=mid+1;
else r=mid;
}
return CJ(d1[l][0]-X2,d1[l][1]-Y2,X1-X2,Y1-Y2)||((l<=r)&&CJ(d1[l+1][0]-X2,d1[l+1][1]-Y2,X1-X2,Y1-Y2));
}
bool find(int l,int r,int e)
{
if(CJ(X1,Y1,a0[l][0],a0[l][1])&&CJ(a0[r][0],a0[r][1],X2,Y2))return CEK(e);
if(l==r)return 0;
int mid=(l+r)>>1;
bool ans=0;
if(CJ(X1,Y1,a0[mid][0],a0[mid][1]))ans=find(l,mid,e<<1);
if(ans)return 1;
return (CJ(a0[mid+1][0],a0[mid+1][1],X2,Y2))?find(mid+1,r,e<<1|1):0;
}
int main()
{
int q,w;
read(n),read(m);
fo(i,1,n)
{
read(a[i].x),read(a[i].y);
}
sort(a+1,a+1+n,PX);
fo(i,1,n)a0[i][0]=a[i].x,a0[i][1]=a[i].y;
build(1,n,1);
fo(I,1,m)
{
X1=read(q),Y1=read(q),X2=read(q),Y2=read(q);
if(CJ(X2,Y2,X1,Y1))swap(X1,X2),swap(Y1,Y2);
Ks=CJ(0,1,X2-X1,Y2-Y1);
ans=find(1,n,1);
if(ans)printf("Y\n");
else printf("N\n");
}
return 0;
}