BZOJ4140 : 共点圆加强版

假设当前询问点为$(A,B)$,那么它在一个以$(x,y)$为圆心的圆里需要满足:

$(x-A)^2+(y-B)^2\leq x^2+y^2$

$2Ax+2By\geq A^2+B^2$

等价于询问所有圆心与$(2A,2B)$的点积的最小值是否小于$A^2+B^2$。

考虑将修改操作二进制分组,分成$O(\log n)$段连续的修改区间,每一段建立上下凸壳维护,查询时在凸壳上三分。

时间复杂度$O(n\log^2n)$,常数很小。

 

#include<cstdio>
#include<algorithm>
#define N 500010
int n,m,op,t,q[30],r1[30],r2[30],flag;double A,B,C,D;
struct P{double x,y;}a[N],b[N],q1[N],q2[N];
inline bool cmp1(const P&a,const P&b){return a.x==b.x?a.y>b.y:a.x<b.x;}
inline bool cmp2(const P&a,const P&b){return a.x==b.x?a.y<b.y:a.x<b.x;}
inline void update(){
  while(t&&m-q[t]==q[t]-q[t-1])t--;q[++t]=m;
  int i,cnt=0,L=q[t-1]+1,R;
  for(i=L;i<=m;i++)b[cnt++]=a[i];
  std::sort(b,b+cnt,cmp1);
  for(q1[R=L]=b[0],i=1;i<cnt;q1[++R]=b[i++])while(R>L&&(q1[R].y-q1[R-1].y)*(b[i].x-q1[R].x)<=(b[i].y-q1[R].y)*(q1[R].x-q1[R-1].x))R--;
  r1[t]=R;
  std::sort(b,b+cnt,cmp2);
  for(q2[R=L]=b[0],i=1;i<cnt;q2[++R]=b[i++])while(R>L&&(q2[R].y-q2[R-1].y)*(b[i].x-q2[R].x)>=(b[i].y-q2[R].y)*(q2[R].x-q2[R-1].x))R--;
  r2[t]=R;
}
inline double mul(const P&b){return A*b.x+B*b.y;}
inline void ask1(int l,int r){
  int m1,m2;double s1,s2;
  while(l<=r){
    int len=(r-l)/3;
    if((s1=mul(q1[m1=l+len]))<(s2=mul(q1[m2=r-len]))){
      if(s1<C){flag=1;return;}
      r=m2-1;
    }else{
      if(s2<C){flag=1;return;}
      l=m1+1;
    }
  }
}
inline void ask2(int l,int r){
  int m1,m2;double s1,s2;
  while(l<=r){
    int len=(r-l)/3;
    if((s1=mul(q2[m1=l+len]))<(s2=mul(q2[m2=r-len]))){
      if(s1<C){flag=1;return;}
      r=m2-1;
    }else{
      if(s2<C){flag=1;return;}
      l=m1+1;
    }
  }
}
inline void ask(){
  flag=0;
  for(int i=1;i<=t;i++){
    if(B<0)ask1(q[i-1]+1,r1[i]);else ask2(q[i-1]+1,r2[i]);
    if(flag)return;
  }
}
int main(){
  scanf("%d",&n);
  while(n--){
    scanf("%d%lf%lf",&op,&A,&B);A+=D,B+=D;
    if(!op)a[++m].x=A,a[m].y=B,update();
    else{
      if(!m){puts("No");continue;}
      C=A*A+B*B,A+=A,B+=B,ask();
      if(flag)puts("No");else puts("Yes"),D++;
    }
  }
  return 0;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值