[二进制分组] BZOJ4140. 共点圆加强版

来源:互联网 发布:smtp.gmail.com 端口 编辑:程序博客网 时间:2024/05/22 05:05

没做过在线版…

(xxi)2+(yyi)=x2i+y2i

yi=x2+y22yxy×xi

k=xyd=x2+y22y

就相当于是判断对于所有点 kxi+dy 的最小值是否大于零

发现这样的点就在下凸包上

二进制分组就相当于把点分成 logn 个组,也就是把 n 分成2的幂次的和

比如 13=23+22+20,就把13个点分成8个点,4个点,1个点三个组

每次加点的时候新开一个组,如果这个组与前一个组的大小相同就合并这两个组,每次合并暴力重构。

这样每次查询就相当于在log个凸包上二分一下

复杂度O(nlog2n)

#include <cstdio>#include <iostream>#include <algorithm>#include <vector>#include <cmath>#define fi first#define se secondusing namespace std;typedef pair<double,double> PAR;const int N=500010;const double eps=-1e-7;int q,n,cnt,t;PAR a[N];bool operator <(PAR a,PAR b){    return a.fi<b.fi || (a.fi==b.fi && a.se<b.se);}inline double GetK(PAR y,PAR x){    return (y.se-x.se)/(y.fi-x.fi);}struct PART{    vector<PAR> p,Q1;    int tot,qt1;    void push(PAR x){        tot++; p.push_back(x);    }    void clear(){        p.clear(); Q1.clear();        tot=qt1=0;    }    void build(){        for(int i=0;i<tot;i++) a[i]=p[i];        sort(a,a+tot);        qt1=1; Q1.resize(tot+5); Q1[0]=a[0];        for(int i=1;i<tot;i++){            while(qt1>1 && GetK(Q1[qt1-1],Q1[qt1-2])-GetK(a[i],Q1[qt1-1])>=eps) qt1--;            Q1[qt1++]=a[i];        }        Q1.resize(qt1+5);    }    PAR query(vector<PAR> Q,int qt,double k){        int l=0,r=qt-1,mid,ret=0;        while(l<=r){            mid=l+r>>1;            if(mid==0 || k-GetK(Q[mid],Q[mid-1])>eps) l=(ret=mid)+1;            else r=mid-1;        }        //printf("%d\n",ret);        return Q[ret];    }    bool query(double x,double y){        double k=-x/y,b=(x*x+y*y)/(2*y);        /*for(int i=0;i<qt1;i++)            printf("%lf %lf\n",Q1[i].fi,Q1[i].se);*/        PAR cur=query(Q1,qt1,k);        return 2*x*cur.fi+2*y*cur.se-x*x-y*y>1e-7;    }}B[20];inline void Add(double x,double y){    B[++t].push(PAR(x,y));    while(t>1 && B[t].tot==B[t-1].tot){        for(int i=0;i<B[t].tot;i++)            B[t-1].push(B[t].p[i]);        B[t].clear(); t--;    }    B[t].build();}inline int Query(double x,double y){    if(t==0) return 0;    for(int i=1;i<=t;i++)        if(!B[i].query(x,y)) return 0;    return 1;}int main(){    scanf("%d",&q);    for(int i=1;i<=q;i++){        double x,y; int opt;        scanf("%d%lf%lf",&opt,&x,&y);        x+=cnt; y+=cnt;        if(opt==0) Add(x,y);        else puts(Query(x,y)?(cnt++,"Yes"):"No");       }    return 0;}
原创粉丝点击