[BZOJ2961] 共點圓 [cdq分治+凸包]

題面

BZOJ傳送門php

思路

首先考慮一個點$(x_0,y_0)$何時在一個圓$(x_1,y_1,\sqrt{x_1^2+y_1^2})$內node

顯然有:$x_1^2+y_1^2\geq (x_0-x_1)^2+(y_0-y_1)^2$ios

化簡:$2x_0x_1+2y_0y_1\geq x_0^2+y_0^2$git

全部含$x_1,y_1$的項挪到同一邊,除掉一個$2y_0$(假設它是正的),獲得:spa

$y_1\geq -\frac{x_0}{y_0}x_1+\frac{x_0^2+y_0^2}{2y_0}$指針

若是是負的:code

$y_1\leq -\frac{x_0}{y_0}x_1+\frac{x_0^2+y_0^2}{2y_0}$排序

DUANG!半平面來了get

那麼如今的詢問變成了:給定一個半平面,問是否是全部的點都在這個半平面的上方(或者下方)string

顯然,咱們若是維護了全部輸入節點的上下凸包,這個問題就迎刃而解了

衆所周知,維護動態上下凸殼能夠用$set$或者平衡樹作到$O(n\log n)$

然而博主並不想寫這種東西

因此他寫了很是沙雕的cdq分治23333

分治

分治開始以前先按照全部詢問點的斜率排個序(非詢問點無論)

咱們對時間順序分治

進入分治後,首先分治左區間,返回按照橫座標排好序的左區間全部點

求出左區間中全部非詢問的點的上下凸殼

而後對右邊的全部詢問,由於一開始排好序了,因此直接在凸殼上順次雙指針過去

注意:$y_0 > 0$的時候全部點在直線上方,用的是下凸包,反之亦然

最後分治右區間,按照x座標歸併排序,合併左右區間

就是個很模板的cdq斜率分治

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cassert>
#include<cmath>
#define sqr(x) ((x)*(x))
#define eps 1e-10
#define ll long long
using namespace std;
inline int read(){
    int re=0,flag=1;char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') flag=-1;
        ch=getchar();
    }
    while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    return re*flag;
}
struct node{
    double x,y,k;
    int id,qid,op;
    inline friend double slope(const node &a,const node &b){return ((fabs(a.x-b.x)<eps)?(1e30):((a.y-b.y)/(a.x-b.x)));}
    inline friend double dis(const node &a,const node &b){return sqrt(sqr(a.x-b.x)+sqr(a.y-b.y));}
    inline friend double rad(const node &a){return sqrt(sqr(a.x)+sqr(a.y));}
}a[500010],tmp[500010],q1[500010],q2[500010];//q1 up q2 down
int n,top1,top2;bool ans[500010];
inline bool cmp(const node &a,const node &b){return a.k<b.k;}
void solve(int l,int r){
    if(l==r) return;
    int i,t1,t2,mid=(l+r)>>1;

    t1=l;t2=mid+1;
    for(i=l;i<=r;i++){
        if(a[i].id<=mid) tmp[t1++]=a[i];
        else tmp[t2++]=a[i];
    }
    memcpy(a+l,tmp+l,sizeof(node)*(r-l+1));

    solve(l,mid);

    top1=top2=0;
    for(i=l;i<=mid;i++){
        if(a[i].op) continue;
        while(top1>1&&slope(q1[top1-1],q1[top1])<slope(q1[top1],a[i])+eps) top1--;
        q1[++top1]=a[i];
        while(top2>1&&slope(q2[top2-1],q2[top2])+eps>slope(q2[top2],a[i])) top2--;
        q2[++top2]=a[i];
    }

    t1=t2=1;
    for(i=mid+1;i<=r;i++){
        if(!a[i].op) continue;
        if(a[i].y>0){
            while(t2<top2&&slope(q2[t2],q2[t2+1])<a[i].k) t2++;
            if(t2<=top2) ans[a[i].qid]&=(dis(a[i],q2[t2])<rad(q2[t2]));
        }
        else{
            while(t1<top1&&slope(q1[top1-1],q1[top1])<a[i].k) top1--;
            if(t1<=top1) ans[a[i].qid]&=(dis(a[i],q1[top1])<rad(q1[top1]));
        }
    }

    solve(mid+1,r);

    t1=l;t2=mid+1;
    for(i=l;i<=r;i++){
        if(t2==r+1||(t1<=mid&&a[t1].x<a[t2].x)) tmp[i]=a[t1++];
        else tmp[i]=a[t2++];
    }
    memcpy(a+l,tmp+l,sizeof(node)*(r-l+1));
}
int main(){
    n=read();int i,flag=0,cntq=0;
    for(i=1;i<=n;i++){
        scanf("%d%lf%lf",&a[i].op,&a[i].x,&a[i].y);
        a[i].id=i;
        if(a[i].op){
            a[i].qid=++cntq;
            if(flag) ans[cntq]=1;
            if(a[i].y) a[i].k=-a[i].x/a[i].y;
            else a[i].k=1e30;
        }
        else flag=1;
    }
    sort(a+1,a+n+1,cmp);
    solve(1,n);
    for(i=1;i<=cntq;i++) puts(ans[i]?"Yes":"No");
}
相關文章
相關標籤/搜索