BZOJ2961 共点圆
小学数学题
题意进行转化:询问点 \((X,Y)\),是否满足 \(\forall_{i \in S} (X-x_i)^2 + (Y-y_i)^2 \le x_i^2 + y_i^2\)。
简单化简一下得到:\(X^2 + Y^2 \le 2Xx_i + 2Yy_i\)。
也就是要维护 \(2Xx_i + 2Yy_i\) 的最小值。
\(2Xx_i + 2Yy_i < 2Xx_j + 2Yy_j\)
\(= X(x_i-x_j) < Y(y_j-y_i)\)
就可以发现最小值只可能出现在凸包上,分治维护凸包即可。
点击查看代码
#include<bits/stdc++.h>
#include<ctime>
#define fir first
#define sec second
#define int long long
#define double long double
#define lowbit(x) x&(-x)
#define mkp(a,b) make_pair(a,b)
using namespace std;
typedef pair<int,int> pir;
inline int read(){
int x=0,f=1; char c=getchar();
while(!isdigit(c)){if(c=='-') f=-1; c=getchar();}
while(isdigit(c)){x=x*10+(c^48); c=getchar();}
return x*f;
}
const int inf=1e18,N=5e5+5;
int n,m,s,cnt;
double mn[N];
struct ques{double x,y; int r,id;};
struct node{double x,y;}p[N],Tm[N],a[N],b[N],Q[N];
inline bool cmp(node a,node b){return a.x<b.x;}
int m1,m2;
inline int find(double x,double y,node* S,int sz){
int l=2,r=sz,res=1;
while(l<=r){
int mid=(l+r)>>1;
if(x*S[mid].x+y*S[mid].y<S[mid-1].y*y+S[mid-1].x*x) l=mid+1,res=mid;
else r=mid-1;
}
return res;
}
inline void solve(int L,int R,vector<ques> P){
s=0;
if(L==R){
for(auto Tmp:P){
double x=Tmp.x,y=Tmp.y;
int id=Tmp.id;
mn[id]=min(mn[id],2*p[L].x*x+2*p[L].y*y);
}
return ;
}
if(P.empty()) return ;
for(int i=L;i<=R;i++) Tm[++s]=p[i];
sort(Tm+1,Tm+s+1,cmp);
m1=m2=0;
for(int i=1;i<=s;i++){
while(m1&&(a[m1].x==Tm[i].x&&a[m1].y<Tm[i].y)) m1--;
if(m1&&a[m1].x==Tm[i].x) continue;
while(m1>1&&(Tm[i].y-a[m1].y)*(a[m1].x-a[m1-1].x)>(a[m1].y-a[m1-1].y)*(Tm[i].x-a[m1].x)) m1--;
a[++m1]=Tm[i];
}
for(int i=1;i<=s;i++){
while(m2&&(b[m2].x==Tm[i].x&&b[m2].y>Tm[i].y)) m2--;
if(m2&&b[m2].x==Tm[i].x) continue;
while(m2>1&&(Tm[i].y-b[m2].y)*(b[m2].x-b[m2-1].x)<(b[m2].y-b[m2-1].y)*(Tm[i].x-b[m2].x)) m2--;
b[++m2]=Tm[i];
}
int mid=(L+R)>>1;
vector<ques> e1,e2;
for(auto Tmp:P){
double x=Tmp.x,y=Tmp.y;
int r=Tmp.r,id=Tmp.id;
if(R<=r){
int it=find(x,y,a,m1);
mn[id]=min(mn[id],2*a[it].x*x+2*a[it].y*y);
it=find(x,y,b,m2);
mn[id]=min(mn[id],2*b[it].x*x+2*b[it].y*y);
}
else{
e1.push_back(Tmp);
if(r>mid) e2.push_back(Tmp);
}
}
solve(L,mid,e1);
solve(mid+1,R,e2);
}
vector<ques> e;
signed main(){
n=read();
for(int i=1;i<=n;i++){
int opt=read();
double x,y;
scanf("%Lf%Lf",&x,&y);
if(!opt) p[++m]={x,y};
else{
if(!m){
puts("No");
continue;
}
cnt++;
e.push_back(ques{x,y,m,cnt});
Q[cnt]={x,y};
}
}
for(int i=1;i<=cnt;i++) mn[i]=inf;
solve(1,m,e);
double eps=-1e-9;
for(int i=1;i<=cnt;i++){
auto [x,y]=Q[i];
if(eps<=mn[i]-x*x-y*y) puts("Yes");
else puts("No");
}
}