【BZOJ2961】【国家队清华集训2012~2013】—共点圆(CDQ分治+凸包)

传送门

其实也不是很难,但是没考虑周全调了半天……
我还是tcltcl

显然可以直接对圆反演后用平衡树维护动态凸包

考虑到对于一个点(x0,y0),(x_0,y_0),在圆(x,y)(x,y)中即(x0x)2+(y0y)2x2+y2(x_0-x)^2+(y_0-y)^2\le x^2+y^2

化简后即x02+y022x0x2y0yx_0^2+y_0^2-2x_0x\le 2y_0y
y0>0y_0>0

x0y0x+x02+y022y0y-\frac{x_0}{y_0}x+\frac {x_0^2+y_0^2} {2y_0}\le y

y0<0y_0<0的情况类似

发现左边就是一个直线的方程,问题就转化成了判断所有点是否处于这条直线的某一边

发现我们只需要在凸包上二分找到两边斜率卡的那个点判断一下就可以了

对2种情况分别维护一下下凸包和上凸包就可以了
复杂度O(nlog2n)O(nlog^2n)

其实可以归并排序和对询问的斜率归并排序做到O(nlogn)O(nlogn)
但是结构体太丑常数太大也懒得写了

注意特判y0=0y_0=0的情况

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    char ch=getchar();
    int res=0,f=1;
    while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=getchar();
    return res*f;
}
const int N=500005;
const double eps=1e-9;
const double inf=1e20;
struct point{
    double x,y;
    point(double _x=0,double _y=0):x(_x),y(_y){}
    friend inline point operator +(const point &a,const point &b){
        return point(a.x+b.x,a.y+b.y);
    }
    friend inline point operator -(const point &a,const point &b){
        return point(a.x-b.x,a.y-b.y);
    }
    friend inline double operator *(const point &a,const point &b){
        return a.x*b.y-a.y*b.x;
    }
    friend inline double getk(const point &a,const point &b){
        return fabs(a.x-b.x)<=eps?inf:(a.y-b.y)/(a.x-b.x);
    }
    inline double dis(){
        return x*x+y*y;
    }
}q[N],q1[N],q2[N];
struct ask{
    point p;double k,b;
    inline void read(){
        scanf("%lf%lf",&p.x,&p.y);
    }
    int op,id,ans;
}p[N],tmp[N];
inline double P(double x){
    return x*x;
}
inline bool comp(const ask&a,const ask&b){
    return a.id<b.id;
}
int n,tot,cnt1,cnt2;
inline bool checkup(const point &a){
    double k=-a.x/a.y,b=(P(a.x)+P(a.y))/(2*a.y);
    int l=1,r=cnt1,res=l;
    while(l<=r){
        int mid=(l+r)>>1;
        if(k-getk(q1[mid+1],q1[mid])>-eps)r=mid-1,res=mid;
        else l=mid+1;
    }
    return (q1[res].x*k+b)-q1[res].y>-eps;
}
inline bool checkdown(const point &a){
    double k=-a.x/a.y,b=(P(a.x)+P(a.y))/(2*a.y);
    int l=1,r=cnt2,res=r;
    while(l<=r){
        int mid=(l+r)>>1;
        if(k-getk(q2[mid+1],q2[mid])<eps)r=mid-1,res=mid;
        else l=mid+1;
    }
    return (q2[res].x*k+b)-q2[res].y<eps;
}
void cdq(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    double mx=-inf,mn=inf;
    cdq(l,mid),cdq(mid+1,r);
    tot=0,cnt1=0,cnt2=0;
    for(int i=l;i<=mid;i++){
        if(p[i].op==0)q[++tot]=p[i].p,mx=max(mx,p[i].p.x),mn=min(mn,p[i].p.x);
    }
    q1[cnt1=1]=q[1],q2[cnt2=1]=q[1];
    for(int i=2;i<=tot;i++){
        while(cnt1>=2&&getk(q[i],q1[cnt1-1])-getk(q1[cnt1],q1[cnt1-1])>-eps)cnt1--;
        q1[++cnt1]=q[i];
    }
    for(int i=2;i<=tot;i++){
        while(cnt2>=2&&getk(q[i],q2[cnt2-1])-getk(q2[cnt2],q2[cnt2-1])<eps)cnt2--;
        q2[++cnt2]=q[i];
    }
    for(int i=mid+1;i<=r;i++){
        point a=p[i].p;
        if(p[i].op){
            if(a.y<-eps){
                if(!checkup(a))p[i].ans=0;
            }
            else if(a.y>eps){
                if(!checkdown(a))p[i].ans=0;
            }
        }
    }
    for(int i=1;i<=cnt1;i++)q1[i]=point(0,0);
    for(int i=1;i<=cnt2;i++)q2[i]=point(0,0);
    cnt1=l,cnt2=mid+1,tot=l-1;
    while(cnt1<=mid&&cnt2<=r){
        if(p[cnt1].p.x<p[cnt2].p.x)tmp[++tot]=p[cnt1++];
        else tmp[++tot]=p[cnt2++];
    }
    while(cnt1<=mid)tmp[++tot]=p[cnt1++];
    while(cnt2<=r)tmp[++tot]=p[cnt2++];
    for(int i=l;i<=r;i++){
        p[i]=tmp[i];
    }
}
bool flag=0;
int main(){
    n=read();double mx=-1e9,mn=1e9;
    for(int i=1;i<=n;i++){
        p[i].op=read(),p[i].id=i,p[i].read();
        point a=p[i].p;
        if(p[i].op==0)flag=1,mx=max(mx,a.x),mn=min(mn,a.x);
        else {
			p[i].ans=flag;
        	if(fabs(a.y)<eps){
        	    if(a.x>eps&&mn*2-a.x<eps)p[i].ans=0;
        	    if(a.x<-eps&&mx*2-a.x>-eps)p[i].ans=0;
        	}
		}
    }
    cdq(1,n);
    sort(p+1,p+n+1,comp);
    for(int i=1;i<=n;i++){
        if(p[i].op==1){
            if(p[i].ans)puts("Yes");
            else puts("No");
        }
    }
}
posted @ 2019-03-18 19:46  Stargazer_cykoi  阅读(162)  评论(0编辑  收藏  举报