%%% PoPoQQQ :http://blog.csdn.net/PoPoQQQ/article/details/42318247
“题目大意:给定平面,多次插入点和圆,每次插入点时询问当前插入的点是否在之前插入的所有圆中并且至少在一个圆中
直接用数据结构维护这些点和圆不是很好写,我们考虑CDQ分治
对于每层分治,我们需要对于[mid+1,r]中的每个点求出[l,mid]中是否所有的圆都覆盖了这个点
设点的坐标为(x0,y0),那么这个点在所有圆内必须满足对于所有的圆心(x,y),(x-x0)^2+(y-y0)^2<=x^2+y^2,即2*x*x0+2*y*y0>=x0^2+y0^2
我们发现上面的式子是一个半平面,斜率为-x0/y0,如果所有的圆心都在这个半平面中,那么这个点就在所有的圆内。
我们可以对所有的圆心做一个凸包(上下凸包都要做),保证[mid+1,r]部分斜率递增,然后对于每个点对应的半平面,去凸包上查找卡到的点
如果这个点在卡到的圆之内 那么它就在[l,mid]中所有圆之内 反之则不在
然后就正常做好了- - 如果一个点的y0为正 就在下凸包上查询 反之则在上凸包上查询
由于斜率递增 所以下凸包应该维护一个队列,而上凸包则需要维护一个栈 y0=0的情况要特判
此外注意左侧没有圆的情况- -”
详见2013 xhr 论文
PS 调戏了半天 Quickhull打错了
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; inline int dcmp(double a,double b){ if (fabs(a-b)<1e-15) return 0; if (a<b) return -1; return 1; } struct Point{ double x,y; Point(double x=0,double y=0):x(x),y(y) { } bool operator < (const Point &B) const{ return dcmp(x,B.x)==0?y<B.y:x<B.x; } void read(){ scanf("%lf%lf",&x,&y); } friend double Cross(Point p1,Point p2,Point p0){ return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y); } friend double calc(Point p1,Point p2){ if (dcmp(p1.x,p2.x)==0) return 1e100; return (p2.y-p1.y)/(p2.x-p1.x); } friend double Distance(const Point p1,const Point p2=Point(0,0)) { return sqrt( (p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y) ); } }P[500005],hull[500005]; double s[500005]; int num,cnt; struct event{ int f,idx; Point p; }eve[500005]; int n,icnt; int ans[500005]; inline void Qhull(int l,int r,Point a,Point b) { int i=l-1,j=r+1,x=l; for (int k=l;k<=r;k++) if (dcmp(s[k],s[x])>0 || (dcmp(s[k],s[x])==0 && P[x]<P[k])) x=k; Point y=P[x]; for (int k=l;k<=r;k++) { s[++i]=Cross(P[k],a,y); if (dcmp(s[i],0)>0) swap(P[k],P[i]); else s[i--]=0; } for (int k=r;k>=l;k--) { s[--j]=Cross(P[k],y,b); if (dcmp(s[j],0)>0) swap(P[j],P[k]); else s[j++]=0; } if (l<=i) Qhull(l,i,a,y); hull[++cnt]=y; if (j<=r) Qhull(j,r,y,b); } inline void QHULL(int l,int r){ num=cnt=0; int x=1; for (int i=l;i<=r;i++) if (eve[i].f==0) { P[++num]=eve[i].p; if (P[num]<P[x]) x=num; s[num]=0; } if (num==0) return; swap(P[1],P[x]); hull[++cnt]=P[1]; if (num>=2) Qhull(2,num,P[1],P[1]); } double sk[500005],xk[500005]; int scnt,xcnt; int lp,rp; inline void cdq(int l,int r){ if (l==r) return; int mid=(l+r)>>1; cdq(l,mid); cdq(mid+1,r); QHULL(l,mid); if (cnt==0) return; lp=1,rp=1; for (int i=1;i<=cnt;i++) { if (hull[i].x<hull[lp].x) lp=i; if (hull[i].x>hull[rp].x) rp=i; } sk[scnt=1]=-1e130; for (int i=rp;i!=lp;i=i==1?cnt:i-1) { sk[++scnt]=calc(hull[i],hull[i==1?cnt:i-1]); if (sk[scnt]==1e100 && scnt==2) sk[scnt]=-1e100; } sk[++scnt]=1e130; xk[xcnt=1]=-1e130; for (int i=lp;i!=rp;i=i==1?cnt:i-1) { xk[++xcnt]=calc(hull[i],hull[i==1?cnt:i-1]); if (xk[xcnt]==1e100 && xcnt==2) xk[xcnt]=-1e100; } xk[++xcnt]=1e130; int iter,pos; double K; Point p; for (int i=mid+1;i<=r;i++) if (eve[i].f==1) { if (eve[i].idx==367) int c=1; p=eve[i].p; K=-p.x/p.y; if (dcmp(p.y,0)>0) { iter=lower_bound(xk+1,xk+xcnt+1,K)-xk; pos=(((lp-(iter-1)+1)%cnt)+cnt)%cnt; if (pos==0) pos=cnt; if (Distance(hull[pos])<Distance(hull[pos],p)) ans[eve[i].idx]=0; } else if (dcmp(p.y,0)<0) { iter=lower_bound(sk+1,sk+scnt+1,K)-sk; pos=(((rp-(iter-1)+1)%cnt)+cnt)%cnt; if (pos==0) pos=cnt; if (Distance(hull[pos])<Distance(hull[pos],p)) ans[eve[i].idx]=0; } else if (dcmp(p.y,0)==0) { if (p.x>0) pos=lp; else pos=rp; if (Distance(hull[pos])<Distance(hull[pos],p)) ans[eve[i].idx]=0; } } } int main() { freopen("t.in","r",stdin); freopen("t.out","w",stdout); scanf("%d",&n); int flag=0; for (int i=1;i<=n;i++) { scanf("%d",&eve[i].f),eve[i].p.read(); if (eve[i].f==1) eve[i].idx=++icnt,ans[icnt]=flag; else flag=1; } cdq(1,n); for (int i=1;i<=icnt;i++) if (ans[i]) printf("Yes\n"); else printf("No\n"); return 0; }