[二进制分组] BZOJ 4140 共点圆加强版

其实做法是跟离线一模一样的 只不过强制在线
可以使用二进制分组这个技巧
详见xhr论文
跑的比分治快是smg
一天到晚做数据结构的傻逼选手

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#define pb push_back
using namespace std;
typedef double ld;

const ld PI=acos(-1.0);

inline int sgn(ld t){
  if (fabs(t)<1e-8) return 0;
  return t<0?-1:1;
}

struct PP{
  ld x,y;
  void read() { scanf("%lf%lf",&x,&y); }
  void print() { printf("%lf %lf\n",x,y); }
  PP(ld x=0,ld y=0):x(x),y(y) { }
  friend PP operator + (PP A,PP B){ return PP(A.x+B.x,A.y+B.y); }
  friend PP operator - (PP A,PP B){ return PP(A.x-B.x,A.y-B.y); }
  friend ld operator * (PP A,PP B){ return A.x*B.y-B.x*A.y; }
  bool operator < (const PP &B) const{
    return x==B.x?y<B.y:x<B.x;
  }
};

int tot;
int size[25];
vector<PP> pt[25];
vector<ld> ang[25];

int Q;

PP lst[500005]; int pnt;
PP sta[500005]; int top;
PP O;

inline bool cmp(PP A,PP B){
  return sgn((A-O)*(B-O))>0;
}

inline void Hull(){
  for (int i=2;i<=pnt;i++)
    if (lst[i]<lst[1])
      swap(lst[i],lst[1]);
  O=lst[1];
  sort(lst+2,lst+pnt+1,cmp);
  top=0;
  for (int i=1;i<=pnt;i++){
    while (top>1 && sgn((lst[i]-sta[top])*(sta[top]-sta[top-1]))>=0) top--;
    sta[++top]=lst[i];
  }
}

inline ld Tran(ld a){
  return a<=-PI/2?a+2*PI:a;
}

inline void Ins(PP p){
  pt[++tot].pb(p); size[tot]=1; pnt=0;
  lst[++pnt]=p;
  while (tot>1 && size[tot]==size[tot-1]){
    for (int i=0;i<(int)pt[tot-1].size();i++)
      lst[++pnt]=pt[tot-1][i];
    size[tot-1]+=size[tot];
    size[tot]=0; pt[tot].clear(); ang[tot].clear();
    tot--;
  }
  Hull();
  pt[tot].clear(),ang[tot].clear();
  if (top>1){
    for (int i=1;i<top;i++)
      pt[tot].pb(sta[i]),ang[tot].pb(Tran(atan2(sta[i+1].y-sta[i].y,sta[i+1].x-sta[i].x)));
    pt[tot].pb(sta[top]),ang[tot].pb(Tran(atan2(sta[1].y-sta[top].y,sta[1].x-sta[top].x)));
  }else{
    pt[tot].pb(sta[1]);
  }
}

inline bool Query(PP p){
  ld ag,x0=p.x,y0=p.y;
  if (y0>0) ag=Tran(atan2(-x0,y0)); else ag=Tran(atan2(x0,-y0));
  for (int i=1;i<=tot;i++){
    int it;
    //    for (int j=0;j<(int)ang[i].size();j++)
    //    printf("%lf ",ang[i][j]);
    //    printf("\n");
    if (pt[i].size()==1)
      it=0;
    else
      it=lower_bound(ang[i].begin(),ang[i].end(),ag)-ang[i].begin();
    //    pt[i][it].print();
    if (!(sgn(2*x0*pt[i][it].x+2*y0*pt[i][it].y-x0*x0-y0*y0)>=0))
      return 0;
  }
  return 1;
}

int main(){
  int order; PP p; int mask=0;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  scanf("%d",&Q);
  int f=0;
  while (Q--){
    scanf("%d",&order); p.read(); 
    p.x+=mask; p.y+=mask;
    if (order==0)
      f=1,Ins(p);
    else{
      if (!f) { printf("No\n"); continue; }
      Query(p)?(printf("Yes\n"),mask++):printf("No\n");
    }
  }
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值