bzoj2961&&bzoj4140 共点圆
题目描述
在平面直角坐标系中,Wayne需要你完成n次操作,操作只有两种:
1.0 x y。表示在坐标系中加入一个以(x, y)为圆心且过原点的圆。
2.1 x y。表示询问点(x, y)是否在所有已加入的圆的内部(含圆周),且至少在一个圆内部(含圆周)。
为了减少你的工作量,题目保证圆心严格在x轴上方(纵坐标为正),且横坐标非零。
输入格式
第1行一个整数n。
接下来n行,每行第一个数是0或1,分别表示两种操作。
接着有两个实数x和y,具体意义见题面。
输出格式
对于每个询问操作,如果点在所有已加入的圆内(或圆周上),则输出“Yes”(不含引号);否则输出“No”(不含引号)。
数据范围
对于100%的数据,n≤500000,所有坐标绝对值不超过10000。
-
题解
- 在一个圆内$(x-a)^2 + (y-b)^2 <= x^2 + y^2$,化简得$ax + by >= \frac{a^2 + b^2}{2}$,
- 右边是定值,求出$ax+by$的最小值即可判断,做法类似bzoj3533
- 如果对时间分治,每次对区间左边求凸包,$n \ logn$可以实现;
- bzoj4140要求强制在线,可以采用二进制分组
- 由于只会从后面查询,类似树状数组,每次重构末尾的$lowbit$位的凸包,查询不断-=lowbit(i)三分;
- 注意复杂度的理解:
- 考虑$n$位二进制数$N$,$lowbit$为第$i$位的有,$2^{n-i}$个,
- $\sum_{i=0}^{n-1} 2^i \ * \ 2^{n-i} = N \ log_{2} \ N$
1 #include<bits/stdc++.h> 2 #define ld double 3 #define il inline 4 using namespace std; 5 const int N=500010; 6 const ld eps=1e-9; 7 int n,m,st1[N],ed1[N],st2[N],ed2[N],top,cnt; 8 ld mn; 9 il int dcmp(ld x){return fabs(x)<eps?0:x<0?-1:1;} 10 struct P{ 11 ld x,y; 12 P(ld X=0,ld Y=0):x(X),y(Y){}; 13 bool operator <(const P&a)const{return fabs(x-a.x)<eps?y<a.y:x<a.x;} 14 P operator -(const P&a)const{return P(x-a.x,y-a.y);} 15 }q[N],p[N],t[N],Q; 16 ld crs(const P&a,const P&b){return a.x*b.y-a.y*b.x;} 17 ld dot(const P&a,const P&b){return a.x*b.x+a.y*b.y;} 18 void ask(int l,int r){ 19 while(r-l>=3){ 20 int mid=(r-l)/3,mid1=l+mid,mid2=r-mid; 21 if(dot(q[mid1],Q)>dot(q[mid2],Q))l=mid1; 22 else r=mid2; 23 } 24 for(int i=l;i<=r;++i)mn=min(mn,dot(q[i],Q)); 25 } 26 int main(){ 27 #ifndef ONLINE_JUDGE 28 freopen("bzoj2961.in","r",stdin); 29 freopen("bzoj2961.out","w",stdout); 30 #endif 31 scanf("%d",&n); 32 for(int i=1,op;i<=n;++i){ 33 scanf("%d",&op); 34 if(op==0){ 35 m++;scanf("%lf%lf",&p[m].x,&p[m].y); 36 p[m].x+=cnt,p[m].y+=cnt; 37 int l=m-(m&-m)+1,r=m; 38 st1[m]=top=l; 39 for(int j=l;j<=r;++j)t[j]=p[j]; 40 sort(t+l,t+r+1); 41 q[top]=t[l]; 42 for(int j=l+1;j<=r;++j){ 43 while(top>l&&dcmp(crs(q[top]-q[top-1],t[j]-q[top]))<=0)top--; 44 q[++top]=t[j]; 45 } 46 int now=ed1[m]=st2[m]=top; 47 for(int j=r-1;j>=l;--j){ 48 while(top>now&&dcmp(crs(q[top]-q[top-1],t[j]-q[top]))<=0)top--; 49 if(j>l)q[++top]=t[j]; 50 } 51 ed2[m]=top; 52 }else{ 53 scanf("%lf%lf",&Q.x,&Q.y); 54 Q.x+=cnt,Q.y+=cnt; 55 if(!m){puts("No");continue;} 56 mn = 1e18; 57 for(int j=m;j;j-=j&-j){ 58 if(Q.y>0)ask(st1[j],ed1[j]); 59 else ask(st2[j],ed2[j]),mn=min(mn,dot(Q,q[st1[j]])); 60 } 61 if(dcmp(mn*2-Q.x*Q.x-Q.y*Q.y)>=0)puts("Yes"),cnt++; 62 else puts("No"); 63 } 64 } 65 }