zoukankan      html  css  js  c++  java
  • 【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)^2le x^2+y^2

    化简后即x02+y022x0x2y0yx_0^2+y_0^2-2x_0xle 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");
            }
        }
    }
    
  • 相关阅读:
    Azure SQL Storage
    T-SQL quries
    映射盘符
    繁体及其输入法、乱码问题
    匈牙利命名法
    C++四种转换总结
    windows系统下进程间通信
    Qt 中文字符串问题
    PDB文件详解
    DbgView 无法开启Capture Kernel问题
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145606.html
Copyright © 2011-2022 走看看