将所有点极角排序,建立线段树,线段树每个节点维护该区间内所有点组成的上下凸壳。
对于一个查询,二分查找出相应区间的左右端点,在线段树上得到$O(\log n)$个节点,在相应凸壳上三分查找出与斜边叉积最大的那个点,看看是否为正即可。
时间复杂度$O(n\log^2n)$。
#include<cstdio> #include<algorithm> using namespace std; typedef long long ll; const int N=100010,E=2000000; int n,m,i,c,d,ans[N],g[262150],v[E],nxt[E],ed,cnt,t0,t1; struct P{ int x,y; P(){} P(int _x,int _y){x=_x,y=_y;} P operator-(P b){return P(x-b.x,y-b.y);} ll operator*(P b){return 1LL*x*b.y-1LL*y*b.x;} }a[N],A,B,C,qA[N],qC[N],b[N],q0[N],q1[N]; inline bool cmp(P a,P b){return a*b>0;} inline bool cmp0(P a,P b){return a.x==b.x?a.y>b.y:a.x<b.x;} inline bool cmp1(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;} inline int getl(P x){ int l=1,r=n,mid,t=n+1; while(l<=r)if(x*a[mid=(l+r)>>1]>0)r=(t=mid)-1;else l=mid+1; return t; } inline int getr(P x){ int l=1,r=n,mid,t=0; while(l<=r)if(x*a[mid=(l+r)>>1]<0)l=(t=mid)+1;else r=mid-1; return t; } void add(int x,int a,int b){ if(c<=a&&b<=d){v[++ed]=i;nxt[ed]=g[x];g[x]=ed;return;} int mid=(a+b)>>1; if(c<=mid)add(x<<1,a,mid); if(d>mid)add(x<<1|1,mid+1,b); } inline bool query(int x,P*q,int r){ A=qA[x],C=qC[x]; for(int l=0;l<=r;){ int len=(r-l)/3,m0=l+len,m1=r-len; ll s0=C*(q[m0]-A),s1=C*(q[m1]-A); if(s0>0||s1>0)return 1; if(s0>s1)r=m1-1;else l=m0+1; } return 0; } void dfs(int x,int l,int r){ if(g[x]){ int i; for(cnt=0,i=l;i<=r;i++)b[cnt++]=a[i]; for(sort(b,b+cnt,cmp0),q0[t0=0]=b[0],i=1;i<cnt;i++)if(b[i].x!=b[i-1].x){ while(t0&&1LL*(q0[t0].y-q0[t0-1].y)*(b[i].x-q0[t0].x)<=1LL*(b[i].y-q0[t0].y)*(q0[t0].x-q0[t0-1].x))t0--; q0[++t0]=b[i]; } for(sort(b,b+cnt,cmp1),q1[t1=0]=b[0],i=1;i<cnt;i++)if(b[i].x!=b[i-1].x){ while(t1&&1LL*(q1[t1].y-q1[t1-1].y)*(b[i].x-q1[t1].x)>=1LL*(b[i].y-q1[t1].y)*(q1[t1].x-q1[t1-1].x))t1--; q1[++t1]=b[i]; } for(i=g[x];i;i=nxt[i]){ int j=v[i]; if(ans[j])continue; if(query(j,q0,t0)){ans[j]=1;continue;} if(query(j,q1,t1))ans[j]=1; } } if(l==r)return; int mid=(l+r)>>1; dfs(x<<1,l,mid),dfs(x<<1|1,mid+1,r); } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ read(n),read(m); for(i=1;i<=n;i++)read(a[i].x),read(a[i].y); sort(a+1,a+n+1,cmp); for(i=1;i<=m;i++){ read(A.x),read(A.y),read(B.x),read(B.y); if(A*B<0)swap(A,B); qA[i]=A,qC[i]=B-A; c=getl(A),d=getr(B); if(c<=d)add(1,1,n); } dfs(1,1,n); for(i=1;i<=m;i++)puts(ans[i]?"Y":"N"); return 0; }