[BZOJ2961]共点圆-[凸包+cdq分治]
Description
Solution
考虑对于每一个点:
设圆的坐标为(x,y),点的坐标为(x0,y0)。依题意得,当一个点在圆里,需要满足(x-x0)2+(y-y0)2<=x2+y2。
化简得x02+y02<=2x0*x+2y0*y。
当y0>0,x*(-x0/y0)+0.5y0+x02/(2*y0)<=y,这是一个半平面的式子;当y0<0时同理,但是要变号。
所以对于某个点(x0,y0),我们构造出在它前面所有圆心的凸包。凸包应分为上下。
通过以上式子我们可以得出,当y0>0时应在下凸包上找点(x,y)【该点为直线y=-x0/y0与下凸包的切点,即若此点满足要求,其他任何点都会满足要求。通过这个条件,我们也可以理解把该点理解为2x0*x+2y0*y最小的点】,反之则应该在上凸包上找。
好的让我们假设目前的y0>0,由于凸包上的点(x,y)是按极角排序,x*x0+y*y0是单峰的(这个式子是向量的点乘,其几何意义为:向量a点乘向量b=向量a的长度*向量b的长度*cos(向量a,b的夹角)。所以根据这个定义,证明,就画图吧。qaq正儿八经公式太麻烦了。)上凸包也是一样的。
Code
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; const double eps=1e-11; int n; bool ans[500010]; struct W{ int tp;double x,y; friend double operator *(W a,W b){return a.x*b.y-a.y*b.x;} friend double operator ^(W a,W b){return a.x*b.x+a.y*b.y;} friend W operator -(W a,W b){return W{0,a.x-b.x,a.y-b.y};} friend bool operator <(W a,W b){return (fabs(a.x-b.x)<eps)?a.y<b.y:a.x<b.x;} }w[500010],t[500010],st[2][500010];//st[0]-上凸包,st[1]-下凸包 double ask(W a,W b){return a.x*b.x+a.y*b.y;} bool _ok[500010]; int top0,top1; bool query(int id) { int l,r,mid1,mid2;double minn=1e12; if (w[id].y<0) { l=1;r=top0; while (r-l>2) { mid1=(l*2+r)/3;mid2=(r*2+l)/3; if ((w[id]^st[0][mid1])<(w[id]^st[0][mid2])) r=mid2; else l=mid1; } for (int i=l;i<=r;i++) minn=min(minn,w[id]^st[0][i]); } else { l=1;r=top1; while (r-l>2) { mid1=(l*2+r)/3;mid2=(r*2+l)/3; if ((w[id]^st[1][mid1])<(w[id]^st[1][mid2])) r=mid2; else l=mid1; } for (int i=l;i<=r;i++) minn=min(minn,w[id]^st[1][i]); } if (2*minn-(w[id].x*w[id].x+w[id].y*w[id].y)<eps) ans[id]=0; } void solve(int l,int r) { if (l==r) return; int mid=(l+r)/2,tot=0; solve(l,mid); solve(mid+1,r); for (int i=l;i<=mid;i++) if (!w[i].tp) t[++tot]=w[i]; sort(t+1,t+tot+1); top1=0,top0=0; for (int i=1;i<=tot;i++) { while (top0>1&&(st[0][top0]-st[0][top0-1])*(t[i]-st[0][top0])>-eps) top0--; st[0][++top0]=t[i]; } st[0][top0+1].x=st[0][top0].x;st[0][top0+1].y=-1e12; for (int i=tot;i;i--) { while (top1>1&&(st[1][top1]-st[1][top1-1])*(t[i]-st[1][top1])>-eps) top1--; st[1][++top1]=t[i]; } st[1][top1+1].x=st[1][top1].x;st[1][top1+1].y=1e12; for (int i=mid+1;i<=r;i++) if (w[i].tp&&ans[i]) query(i); } bool _is=0; int main() { scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d%lf%lf",&w[i].tp,&w[i].x,&w[i].y); if (!w[i].tp) _is=1;else ans[i]=_is; } solve(1,n); for (int i=1;i<=n;i++) if (w[i].tp) if (ans[i]) printf("Yes\n");else printf("No\n"); }