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斜率分治
#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"); }