BZOJ 4140 凸包+二进制分组
思路:
$(x_0-x)^2+(y_0-y)^2<=x^2+y^2$
$y>=(-x_0/y_0)x+(x_0^2+y_0^2)/2y0$
这显然就是凸包了
以一个斜率不断向下(上)走 找到第一个接触到的点
离线可以用cdq分治一发 他左边的判一判是不是都符合在圆内
这不能离线就很难搞了
感觉自己代码能力捉鸡 写棵splay估计要调死
强烈安利二进制分组做法
非常强
在log个凸包上 二分一下斜率 判一判 就好了
//By SiriusRen #include <bits/stdc++.h> using namespace std; const int N=500050; const double pi=acos(-1),eps=1e-10; int n,op,flg,tot,num,top,rec,size[55]; struct Point{double x,y;Point(double X=0,double Y=0):x(X),y(Y){}}jy,lst[N],q[N]; Point operator-(Point a,Point b){return Point(a.x-b.x,a.y-b.y);} double operator*(Point a,Point b){return a.x*b.y-a.y*b.x;} bool operator<(Point a,Point b){return a.x==b.x?a.y<b.y:a.x<b.x;} bool cmp(Point a,Point b){return (a-lst[1])*(b-lst[1])>-eps;} vector<Point>vec[30];vector<double>ang[30]; void Tubao(){ for(int i=2;i<=num;i++)if(lst[i]<lst[1])swap(lst[1],lst[i]); sort(lst+2,lst+1+num,cmp),top=0; for(int i=1;i<=num;i++){ while(top>1&&(lst[i]-q[top])*(q[top]-q[top-1])>-eps)top--; q[++top]=lst[i]; } } double A(double x){return x<=-pi/2?x+2*pi:x;} void insert(Point p){ vec[++tot].push_back(p),size[tot]=1,lst[num=1]=p; while(tot>1&&size[tot]==size[tot-1]){ for(int i=0;i<vec[tot-1].size();i++)lst[++num]=vec[tot-1][i]; size[tot-1]+=size[tot],size[tot]=0,vec[tot].clear(),ang[tot].clear(),tot--; } Tubao(),vec[tot].clear(),ang[tot].clear(); if(top>1){ for(int i=1;i<top;i++)vec[tot].push_back(q[i]),ang[tot].push_back(A(atan2(q[i+1].y-q[i].y,q[i+1].x-q[i].x))); vec[tot].push_back(q[top]),ang[tot].push_back(A(atan2(q[1].y-q[top].y,q[1].x-q[top].x))); } else vec[tot].push_back(q[1]); } bool query(){ double angle; angle=jy.y>0?A(atan2(-jy.x,jy.y)):A(atan2(jy.x,-jy.y)); for(int i=1;i<=tot;i++){ op=vec[i].size()==1?0:lower_bound(ang[i].begin(),ang[i].end(),angle)-ang[i].begin(); if(2*jy.x*vec[i][op].x+2*jy.y*vec[i][op].y-jy.x*jy.x-jy.y*jy.y<eps)return 0; }return 1; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%lf%lf",&op,&jy.x,&jy.y),jy.x+=rec,jy.y+=rec; if(op==0)flg=1,insert(jy); else flg&&query()?(puts("Yes"),rec++):puts("No"); } }