BZOJ2961 共點圓

~Cyan~發表於2024-08-29

小學數學題

題意進行轉化:詢問點 \((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");
    }
}

相關文章