problem
也就是说给出平面上的 n n n 个点,对于 m m m 条直线,依次判断这 n n n 个点是否在每条直线的同一侧。是输出 GOOD,不是输出 BAD。
数据范围: n , m ≤ 100000 n,m≤100000 n,m≤100000。
solution
直线与凸包关系的模板题。
可以把凸包每条线的 a t a n 2 atan2 atan2 的值记下来,然后二分找与直线相切的两个点(为了保证单调性,凸包的第一个点选 y y y 最大,且在 y y y 最大时 x x x 最小的点),然后用叉积判一下即可。
注意题目中 n = 0 n=0 n=0 的数据。
code
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define eps 1e-8
using namespace std;
int n,top;
double angle[N];
int sgn(double x) {return x>eps?1:(x<-eps?-1:0);}
struct point{
double x,y;
point(double _x=0,double _y=0):x(_x),y(_y){}
friend point operator+(const point &a,const point &b) {return point(a.x+b.x,a.y+b.y);}
friend point operator-(const point &a,const point &b) {return point(a.x-b.x,a.y-b.y);}
friend double dot(const point &a,const point &b) {return a.x*b.x+a.y*b.y;}
friend double cross(const point &a,const point &b) {return a.x*b.y-a.y*b.x;}
}p[N],stk[N];
bool operator<(const point &a,const point &b){
double now=cross(a-p[1],b-p[1]);
return sgn(now)==0?a.x<b.x:sgn(now)>0;
}
void Graham(){
int pos=1;
for(int i=2;i<=n;++i)
if(p[pos].y<p[i].y||(p[pos].y==p[i].y&&p[pos].x>p[i].x))
pos=i;
swap(p[pos],p[1]),sort(p+2,p+n+1);
stk[++top]=p[1],stk[++top]=p[2];
for(int i=3;i<=n;++i){
while(top>1&&sgn(cross(p[i]-stk[top-1],stk[top]-stk[top-1]))>0) top--;
stk[++top]=p[i];
}
stk[top+1]=stk[1];
for(int i=1;i<=top;++i)
angle[i]=atan2(stk[i+1].y-stk[i].y,stk[i+1].x-stk[i].x);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%lf%lf",&p[i].x,&p[i].y);
if(n!=0) top=0,Graham();
point S,T;
while(~scanf("%lf%lf%lf%lf",&S.x,&S.y,&T.x,&T.y)){
if(n<=1) {puts("GOOD");continue;}
double A1=atan2(T.y-S.y,T.x-S.x),A2=atan2(S.y-T.y,S.x-T.x);
point u=stk[lower_bound(angle+1,angle+top+1,A1)-angle];
point v=stk[lower_bound(angle+1,angle+top+1,A2)-angle];
puts(sgn(cross(S-u,T-u)*cross(S-v,T-v))<=0?"BAD":"GOOD");
}
return 0;
}