在平面直角坐标系中,Wayne需要你完成n次操作,操作只有两种:
1.0 x y。表示在坐标系中加入一个以(x, y)为圆心且过原点的圆。
2.1 x y。表示询问点(x, y)是否在所有已加入的圆的内部(含圆周),且至少在一个圆内部(含圆周)。
为了减少你的工作量,题目保证圆心严格在x轴上方(纵坐标为正),且横坐标非零。
在平面直角坐标系中,Wayne需要你完成n次操作,操作只有两种:
1.0 x y。表示在坐标系中加入一个以(x, y)为圆心且过原点的圆。
2.1 x y。表示询问点(x, y)是否在所有已加入的圆的内部(含圆周),且至少在一个圆内部(含圆周)。
为了减少你的工作量,题目保证圆心严格在x轴上方(纵坐标为正),且横坐标非零。
第1行一个整数n。
接下来n行,每行第一个数是0或1,分别表示两种操作。
接着有两个实数x和y,具体意义见题面。
对于每个询问操作,如果点在所有已加入的圆内(或圆周上),则输出“Yes”(不含引号);否则输出“No”(不含引号)。
思路来自:这里
推荐论文:许昊然 《浅谈数据结构题的几个非经典解法》
#include<cstdio> #include<cmath> #include<algorithm> #include<iostream> #define pf(x) ((x)*(x)) #define IN inline #define inf 1e20 using namespace std; const int N=5e5+5; const double eps=1e-10; struct node{ int opt,p,id; double x,y,k; bool operator <(const node &t)const{ return k<t.k; } }a[N],b[N]; int n,cnt,q[N]; bool ok[N];char s1[30],s2[30],s3[30]; double getk(int x,int y){ if(fabs(a[x].x-a[y].x)<eps) return inf; return (a[x].y-a[y].y)/(a[x].x-a[y].x); } double dis(int x,int y){ return pf(a[x].x-a[y].x)+pf(a[x].y-a[y].y); } //不知道为什么4360 ms巨慢(有人跑788 ms)太弱了! void CDQ(int l,int r){ if(l==r) return ; int mid=l+r>>1,i=1,k=mid+1,j=l,tp=0; for(i=l;i<=r;i++){ if(a[i].id<=mid) b[j++]=a[i]; else b[k++]=a[i]; } for(i=l;i<=r;i++) a[i]=b[i]; CDQ(l,mid);//本题只需要维护上凸包,下凸包是x轴 for(i=l;i<=mid;i++) if(!a[i].opt){ for(;tp>1&&getk(q[tp-1],i)<getk(q[tp-1],q[tp])+eps;tp--); q[++tp]=i; } for(j=1,i=mid+1;i<=r;i++) if(a[i].opt){ for(;j<tp&&getk(q[j],q[j+1])<a[i].k;j++); if(j<=tp&&dis(q[j],0)<dis(q[j],i)) ok[a[i].p]=0; } CDQ(mid+1,r); for(i=j=l,k=mid+1;i<=r;i++){ if((j<=mid&&a[j].x<a[k].x)||k>r) b[i]=a[j++]; else b[i]=a[k++]; } for(i=l;i<=r;i++) a[i]=b[i]; } int main(){ scanf("%s",s1);n=atoi(s1); bool flag=0; for(int i=1;i<=n;i++){ scanf("%s%s%s",s1,s2,s3); a[i].opt=s1[0]-‘0‘;a[i].x=atof(s2);a[i].y=atof(s3); if(a[i].opt) a[i].p=++cnt,ok[cnt]=flag;else flag=1; a[i].k=-a[i].x/a[i].y;a[i].id=i; } sort(a+1,a+n+1);CDQ(1,n); for(int i=1;i<=cnt;i++) puts(ok[i]?"Yes":"No"); return 0; }
原文:http://www.cnblogs.com/shenben/p/6347773.html