题意
支持在平面直角坐标系内进行操作:
1.加入一个圆心在 (x,y) 且过原点的圆
2.询问点 (x,y) 是否被之前加入的所有圆包含(在圆内或圆心上)
强制在线
题解
询问即判断 (X−xi)2+(Y−yi)2≤x2i+y2i 是否成立
整理一下式子,得 −X/Y∗xi+(X2+Y2)/(2∗Y)≤yi
其实左边就是一条直线
令 k=−X/Y,b=(X2+Y2)/(2∗Y)
即所有圆心要在直线 y=kx+b 上方,所以我们可以维护一个下凸包来做
动态凸包太难写,可以用二进制分组(不知道是啥的可以参考xhr的答辩论文)了
对于本题只要对圆心分组后维护 log2n 个凸包,分组改变时直接暴力重构凸包
查询判断的时候二分逼近斜率,找到凸包上那条斜率最接近 k <script type="math/tex" id="MathJax-Element-26">k</script>的直线然后算一下截距即可
#include<cstdio>
#include<algorithm>
#define N 500005
using namespace std;
int n,num,top,cnt,L[N],R[N];
struct node{
double x,y;
node(){}
node(double a,double b):x(a),y(b){}
bool operator < (const node &a) const {
if(x==a.x) return y<a.y;
else return x<a.x;
}
}p[N],s[N];
inline double dir(node a,node b,node c){
return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
}
void insert(node v){
p[++cnt]=v;
L[++top]=cnt;
while(top>1&&cnt-L[top]+1==L[top]-L[top-1]) --top;
sort(p+L[top],p+cnt+1);
int nw=L[top];s[nw]=p[nw];
for(int i=L[top]+1;i<=cnt;++i){
while(nw>L[top]&&dir(s[nw-1],s[nw],p[i])>=0) --nw;
s[++nw]=p[i];
}
R[top]=nw;
}
inline int find(int l,int r,double k){
int mid,res,h=l;
while(l<=r){
mid=l+r>>1;
if(mid==h||k>(s[mid].y-s[mid-1].y)/(s[mid].x-s[mid-1].x)) res=mid,l=mid+1;
else r=mid-1;
}
return res;
}
bool query(double x,double y){
if(!top) return top;
double a=(x*x+y*y)/(2*y),b=-x/y;
for(int i=1;i<=top;++i){
int pos=find(L[i],R[i],b);
if(a+b*s[pos].x>s[pos].y) return 0;
}
return 1;
}
int main(){
freopen("testdata.in","r",stdin);
scanf("%d",&n);
while(n--){
int opt;double x,y;
scanf("%d%lf%lf",&opt,&x,&y);
x+=num,y+=num;
if(!opt) insert((node){x,y});
else{
// ++x,++y;
if(query(x,y)) ++num,puts("Yes");else puts("No");
}
}
return 0;
}