1. 程式人生 > >【雅禮同考9.9】Triangle

【雅禮同考9.9】Triangle

Description

給出一些在二維平面中第一象限的點,
有多個詢問,每次給出兩個點(x,y),(x1,y1),要求頂點為(0,0),(x,y),(x1,y1)的三角形內是否有點,

Solution

我們分別過點(x,y),(0,0)和(0,0),(x1,y1)作兩直線,把兩直線之間的點挑出來,
顯然的,如果三角形記憶體在點,那麼一定在凸包上,
那麼我們維護區間凸包即可,

複雜度:O(nlog2(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; }