没做过在线版…
(x−xi)2+(y−yi)=x2i+y2i
yi=x2+y22y−xy×xi
另 k=−xy,d=x2+y22y
就相当于是判断对于所有点 kxi+d−y 的最小值是否大于零
发现这样的点就在下凸包上
二进制分组就相当于把点分成 ⌊logn⌋ 个组,也就是把 n 分成2的幂次的和
比如
每次加点的时候新开一个组,如果这个组与前一个组的大小相同就合并这两个组,每次合并暴力重构。
这样每次查询就相当于在log个凸包上二分一下
复杂度 O(nlog2n)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#define fi first
#define se second
using namespace std;
typedef pair<double,double> PAR;
const int N=500010;
const double eps=-1e-7;
int q,n,cnt,t;
PAR a[N];
bool operator <(PAR a,PAR b){
return a.fi<b.fi || (a.fi==b.fi && a.se<b.se);
}
inline double GetK(PAR y,PAR x){
return (y.se-x.se)/(y.fi-x.fi);
}
struct PART{
vector<PAR> p,Q1;
int tot,qt1;
void push(PAR x){
tot++; p.push_back(x);
}
void clear(){
p.clear(); Q1.clear();
tot=qt1=0;
}
void build(){
for(int i=0;i<tot;i++) a[i]=p[i];
sort(a,a+tot);
qt1=1; Q1.resize(tot+5); Q1[0]=a[0];
for(int i=1;i<tot;i++){
while(qt1>1 && GetK(Q1[qt1-1],Q1[qt1-2])-GetK(a[i],Q1[qt1-1])>=eps) qt1--;
Q1[qt1++]=a[i];
}
Q1.resize(qt1+5);
}
PAR query(vector<PAR> Q,int qt,double k){
int l=0,r=qt-1,mid,ret=0;
while(l<=r){
mid=l+r>>1;
if(mid==0 || k-GetK(Q[mid],Q[mid-1])>eps) l=(ret=mid)+1;
else r=mid-1;
}
//printf("%d\n",ret);
return Q[ret];
}
bool query(double x,double y){
double k=-x/y,b=(x*x+y*y)/(2*y);
/*for(int i=0;i<qt1;i++)
printf("%lf %lf\n",Q1[i].fi,Q1[i].se);*/
PAR cur=query(Q1,qt1,k);
return 2*x*cur.fi+2*y*cur.se-x*x-y*y>1e-7;
}
}B[20];
inline void Add(double x,double y){
B[++t].push(PAR(x,y));
while(t>1 && B[t].tot==B[t-1].tot){
for(int i=0;i<B[t].tot;i++)
B[t-1].push(B[t].p[i]);
B[t].clear(); t--;
}
B[t].build();
}
inline int Query(double x,double y){
if(t==0) return 0;
for(int i=1;i<=t;i++)
if(!B[i].query(x,y)) return 0;
return 1;
}
int main(){
scanf("%d",&q);
for(int i=1;i<=q;i++){
double x,y; int opt;
scanf("%d%lf%lf",&opt,&x,&y);
x+=cnt; y+=cnt;
if(opt==0) Add(x,y);
else puts(Query(x,y)?(cnt++,"Yes"):"No");
}
return 0;
}