zoukankan      html  css  js  c++  java
  • [BZOJ2961]共点圆-[凸包+cdq分治]

     Description

    传送门

    Solution

    考虑对于每一个点:

    设圆的坐标为(x,y),点的坐标为(x0,y0)。依题意得,当一个点在圆里,需要满足(x-x0)2+(y-y0)2<=x2+y2

    化简得x02+y02<=2x0*x+2y0*y。

    当y0>0,x*(-x0/y0)+0.5y0+x02/(2*y0)<=y,这是一个半平面的式子;当y0<0时同理,但是要变号。

    所以对于某个点(x0,y0),我们构造出在它前面所有圆心的凸包。凸包应分为上下。

    通过以上式子我们可以得出,当y0>0时应在下凸包上找点(x,y)【该点为直线y=-x0/y0与下凸包的切点,即若此点满足要求,其他任何点都会满足要求。通过这个条件,我们也可以理解把该点理解为2x0*x+2y0*y最小的点】,反之则应该在上凸包上找。

    好的让我们假设目前的y0>0,由于凸包上的点(x,y)是按极角排序,x*x0+y*y0是单峰的(这个式子是向量的点乘,其几何意义为:向量a点乘向量b=向量a的长度*向量b的长度*cos(向量a,b的夹角)。所以根据这个定义,证明,就画图吧。qaq正儿八经公式太麻烦了。)上凸包也是一样的。

    Code

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const double eps=1e-11;
    int n;
    bool ans[500010];
    struct W{
        int tp;double x,y;
        friend double operator *(W a,W b){return a.x*b.y-a.y*b.x;}
        friend double operator ^(W a,W b){return a.x*b.x+a.y*b.y;}
        friend W operator -(W a,W b){return W{0,a.x-b.x,a.y-b.y};}
        friend bool operator <(W a,W b){return (fabs(a.x-b.x)<eps)?a.y<b.y:a.x<b.x;}
    }w[500010],t[500010],st[2][500010];//st[0]-上凸包,st[1]-下凸包 
    double ask(W a,W b){return a.x*b.x+a.y*b.y;}
    bool _ok[500010];
    int top0,top1;
    bool query(int id)
    {
        int l,r,mid1,mid2;double minn=1e12;
        if (w[id].y<0)
        {
            l=1;r=top0;
            while (r-l>2)
            {
                mid1=(l*2+r)/3;mid2=(r*2+l)/3;
                if ((w[id]^st[0][mid1])<(w[id]^st[0][mid2])) r=mid2;
                else l=mid1;
            }
            for (int i=l;i<=r;i++) minn=min(minn,w[id]^st[0][i]);
            
        } else
        {
            l=1;r=top1;
            while (r-l>2)
            {
                mid1=(l*2+r)/3;mid2=(r*2+l)/3;
                if ((w[id]^st[1][mid1])<(w[id]^st[1][mid2])) r=mid2;
                else l=mid1;
            }
            for (int i=l;i<=r;i++) minn=min(minn,w[id]^st[1][i]);
        }
        if (2*minn-(w[id].x*w[id].x+w[id].y*w[id].y)<eps) ans[id]=0;
        
    }
    void solve(int l,int r)
    {
        if (l==r) return;
        int mid=(l+r)/2,tot=0;
        solve(l,mid);
        solve(mid+1,r);
        for (int i=l;i<=mid;i++) if (!w[i].tp) t[++tot]=w[i];
        sort(t+1,t+tot+1);
        top1=0,top0=0;
        for (int i=1;i<=tot;i++)
        {
            while (top0>1&&(st[0][top0]-st[0][top0-1])*(t[i]-st[0][top0])>-eps) top0--;
            st[0][++top0]=t[i];
        }
        st[0][top0+1].x=st[0][top0].x;st[0][top0+1].y=-1e12;
        for (int i=tot;i;i--)
        {
            while (top1>1&&(st[1][top1]-st[1][top1-1])*(t[i]-st[1][top1])>-eps) top1--;
            st[1][++top1]=t[i];
        }
        st[1][top1+1].x=st[1][top1].x;st[1][top1+1].y=1e12;
        for (int i=mid+1;i<=r;i++) if (w[i].tp&&ans[i]) query(i);
    }
    bool _is=0;
    int main()
    {
        scanf("%d",&n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d%lf%lf",&w[i].tp,&w[i].x,&w[i].y);
            if (!w[i].tp) _is=1;else ans[i]=_is;
        }
        solve(1,n);
        for (int i=1;i<=n;i++) if (w[i].tp)
         if (ans[i]) printf("Yes
    ");else printf("No
    ");
    }
  • 相关阅读:
    三层架构和MVC模型的常识
    iOS开发之Auto Layout入门
    js-innerHTML
    $(document).ready() 与window.onload的差别
    java jsp+servlet+mysql实现登录网页设计
    ASCII码表
    表单的提交onsubmit事件
    谋哥:社交小游戏App将是下一个金矿!
    各种表
    vue elementui table 双击单元格实现编辑,聚焦,失去焦点,显示隐藏input和span
  • 原文地址:https://www.cnblogs.com/coco-night/p/9508428.html
Copyright © 2011-2022 走看看