首先圆不好处理,可以用一些骚操作:反演。
几何上的(圆)反演是指确定一个反演中心
O
O
O和反演半径
r
r
r,那么对于一条以反演中心为端点的射线上的两点
P
1
,
P
2
P_1,P_2
P1,P2并且
O
P
1
×
O
P
2
=
r
2
OP_1 \times OP_2 = r^2
OP1×OP2=r2,
P
1
P_1
P1是
P
2
P_2
P2的反演后的点,
P
2
P_2
P2是
P
1
P_1
P1的反演后的点。
那么过反演中心的圆将会被反演成一条直线,直线的两侧,有一侧是圆内的点反演而成,另一侧是圆外的点反演而成,那么判断在圆内可以转换为判定在半平面内。
那么可以做半平面交。
但是这是强制在线动态半平面交,就需要使用二进制分组。
这个东西很强,实测不比CDQ分治慢(BZOJ 2961 共点圆),还可以来搞强制在线动态AC自动机。
最后半平面交直接被板就行。
注意一开始没有圆的所有询问输出
N
O
NO
NO.!!!
貌似没有卡我的精度。
AC Code:
#include<bits/stdc++.h>
#define maxn 500005
#define eps 1e-7
#define inf 1e11
using namespace std;
int n;
int sgn(double a){ return a<-eps?-1:a>eps?1:0; }
struct Point{
double x,y;
Point(double x=0,double y=0):x(x),y(y){}
Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
double operator *(const Point &B)const{ return x*B.y-y*B.x; }
Point operator *(const double &B)const{ return Point(x*B,y*B); }
double Len()const{ return sqrt(x*x+y*y); }
}qp[maxn];
int qL[maxn],l,r;
bool inLeft(const Point &P,const Point &A,const Point &B){
return (B-A)*(P-A)>0;
}
bool onLeft(const Point &P,const Point &A,const Point &B){
return sgn((B-A)*(P-A))>=0;
}
/*
bool cmp(const int &u,const int &v){
if(sgn(L[u].ag-L[v].ag)) return L[u].ag < L[v].ag;
return inLeft(L[u].A,L[v].A,L[v].B);
}*/
struct Line{
Point A,B;
double ag;
Line(Point A=0,Point B=0):A(A),B(B){ag=atan2(B.y-A.y,B.x-A.x);}
bool operator <(const Line &B)const{
if(sgn(ag-B.ag)) return ag<B.ag;
return inLeft(A,B.A,B.B);
}
}L[maxn];
int tot;
Point Ipt(const Point &p1,const Point &p2,const Point &p3,const Point &p4){
Point u = p2-p1, v = p4-p3,w=p2-p4;
return p2+(p1-p2)*((w*v)/(u*v));
}
int cnt_g,siz[30];
vector<int>G[30];
vector<double>GP[30];
int main(){
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
scanf("%d",&n);
int sum=0;
double x,y,R=1000;
for(int i=1,op;i<=n;i++){
scanf("%d%lf%lf",&op,&x,&y);x+=sum,y+=sum;
if(op == 0){
Point P = Point(2*x,2*y);
double tmp = P.Len();
P = P * (R * R / (tmp * tmp));
L[++tot]=Line(P,P+Point(y,-x));
siz[++cnt_g] = 0;
G[cnt_g].clear();
G[cnt_g].push_back(tot);
for(;cnt_g>=2 && siz[cnt_g]==siz[cnt_g-1];cnt_g--){
siz[cnt_g-1]++;
int sz1 = G[cnt_g-1].size(), sz2 = G[cnt_g].size();
int u = cnt_g-1 , v = cnt_g;
static int q[maxn];
for(int i=0,j=0,k=0;i<sz1||j<sz2;)
if(i<sz1 && (j>=sz2 || L[G[u][i]]<L[G[v][j]])) q[k++] = G[u][i++];
else q[k++] = G[v][j++];
l=r=0;
qL[r++] = q[0];
for(int i=1,u;i<sz1+sz2;i++)
if(sgn(L[u=q[i]].ag-L[q[i-1]].ag)){
for(;r-l>=2 && !inLeft(qp[r-2],L[u].A,L[u].B);r--);
//for(;r-l>=2 && !inLeft(qp[l],L[u].A,L[u].B);l++);
qL[r++] = u;
if(r-l>=2)
qp[r-2] = Ipt(L[qL[r-2]].A,L[qL[r-2]].B,L[u].A,L[u].B);
}
//for(;r-l>=2 && !inLeft(qp[l],L[qL[r-1]].A,L[qL[r-1]].B);l++);
for(;r-l>=3 && !inLeft(qp[r-2],L[qL[l]].A,L[qL[l]].B);r--);
G[u].resize(r-l);
//printf("@%d %d\n",l,r);
GP[u].resize(r-l-1);
for(int i=l;i<r;i++){
G[u][i-l] = qL[i];
if(i<r-1){
GP[u][i-l]=atan2(qp[i].y-inf,qp[i].x);
}
}
}
}
else{
bool flg = (cnt_g==0);
Point P = Point(x,y);
double tmp = P.Len();
P = P * (R * R / (tmp * tmp));
x = P.x , y = P.y;
double xl = atan2(y-inf,x);
for(int i=1;i<=cnt_g;i++){
int u = G[i][lower_bound(GP[i].begin(),GP[i].end(),xl) - GP[i].begin()];
if(!onLeft(P,L[u].A,L[u].B)){ flg = 1 ; break; }
}
if(!flg) puts("Yes"),sum++;
else puts("No");
}
}
}