BZOJ2961: 共点圆(CDQ分治+凸包)

题面

传送门

题解

这题解法真是多啊……据说可以圆反演转化为动态插入半平面并判断给定点是否在半平面交中,或者化一下改成给定点判断是否所有点都在某一个半平面内……

鉴于圆反演我也不会,这里讲一下直接推的好了

如果一个圆的圆心是\((a,b)\),询问点是\((x,y)\),那么这个询问点在圆心上的条件就是

\[\begin{aligned} (x-a)^2+(y-b)^2\le a^2+b^2 \\ x^2+y^2\le 2ax+2by \\ b\ge -\frac{x}{y}a+\frac{x^2+y^2}{2y} \end{aligned} \]

因为题目中已经保证\(y>0\)所以最后一步没有问题

这就是一个半平面交的形式了,问题转化为每次加入圆心点,每次询问是否所有点都在某一个半平面内

这里又有三种做法了,一个是\(O(n\log n)\)的平衡树动态凸包,一个是\(CDQ\)分治,还有一个二进制分组,后面两个都是\(O(n\log^2 n)\)

鉴于我只会中间那个,我们来讲一下\(CDQ\)分治的吧

因为询问都是点在直线上方的形式,我们可以每次对于左边的点跑一个下凸壳,然后维护斜率,对于每一个询问在下凸壳上二分斜率,然后判断那个点是否在直线下方即可

//minamoto
#include<bits/stdc++.h>
#define R register
#define inline __inline__ __attribute__((always_inline))
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
double readdb()
{
    R double x=0,y=0.1,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(x=ch-'0';(ch=getc())>='0'&&ch<='9';x=x*10+ch-'0');
    for(ch=='.'&&(ch=getc());ch>='0'&&ch<='9';x+=(ch-'0')*y,y*=0.1,ch=getc());
    return x*f;
}
inline int getop(){R char ch;while((ch=getc())>'9'||ch<'0');return ch-'0';}
const int N=5e5+5;const double eps=1e-10;
inline int sgn(R double x){return x<-eps?-1:x>eps;}
inline double abs(R double x){return x<-eps?-x:x;}
struct node{
    double x,y;
    double at,bt;
    inline node(){}
    inline node(R double xx,R double yy):x(xx),y(yy){}
    inline node operator +(const node &b)const{return node(x+b.x,y+b.y);}
    inline node operator -(const node &b)const{return node(x-b.x,y-b.y);}
    inline double operator *(const node &b)const{return x*b.y-y*b.x;}
    inline bool operator <(const node &b)const{return x==b.x?y<b.y:x<b.x;}
    inline double K(){return y/x;}
}p[N],st[N];double sp[N];int top;
struct qwq{int op;node p;}q[N];
void Graham(int n){
    if(n==1)return st[top=1]=p[1],void();
    sort(p+1,p+1+n);
    st[top=1]=p[1];
    fp(i,2,n)if(sgn(p[i].x-st[top].x)){
        while(top>1&&sgn((p[i]-st[top-1])*(st[top]-st[top-1]))>=0)--top;
        st[++top]=p[i];
    }
    fp(i,1,top-1)sp[i]=(st[i+1]-st[i]).K();
}
int n;bool ans[N];int sz[N];
void solve(int l,int r){
    if(l==r)return;
    int mid=(l+r)>>1;
    solve(l,mid),solve(mid+1,r);
    int tot=0,sz;
    fp(i,l,mid)if(!q[i].op)p[++tot]=q[i].p;
    fp(i,mid+1,r)if(q[i].op&&ans[i])++sz;
    if(!tot||!sz)return;
    Graham(tot);
    fp(i,mid+1,r)if(q[i].op&&ans[i]){
        node &c=q[i].p;double k=-c.x/c.y;
        int p=upper_bound(sp+1,sp+top,k)-sp;
        ans[i]&=(c.x*c.x+c.y*c.y<=2*(st[p].x*c.x+st[p].y*c.y));
    }
}
int main(){
//  freopen("testdata.in","r",stdin);
    n=read();
    fp(i,1,n)q[i].op=getop(),q[i].p.x=readdb(),q[i].p.y=readdb(),sz[i]=sz[i-1]+(!q[i].op),ans[i]=sz[i];
    solve(1,n);
    fp(i,1,n)if(q[i].op)puts(ans[i]?"Yes":"No");
    return 0;
}
posted @ 2019-04-13 14:40  bztMinamoto  阅读(385)  评论(1编辑  收藏  举报
Live2D