分析:就是给一些点的坐标,判断它属于哪个区域。容易想到用以此点和右边界外一点为端点的线段与 partition 求相交情况,因为划分线段 partition 是有序的,所以我们可以用二分,求右方向最近相交的是哪一条线段,就可以知道属于哪个区域了。
代码:
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define V Point
using namespace std;
const double eps=1e-8;
const int MAXN=5e3+5;
struct Point{
double x,y;
Point(){}
Point(double _x,double _y):x(_x),y(_y){}
V operator-(Point p){
return Point(x-p.x,y-p.y);
}
};
int dblcmp(double x){
return fabs(x)<eps?0:(x>0?1:-1);
}
double det(V v1,V v2){
return v1.x*v2.y-v1.y*v2.x;
}
bool cross(Point a,Point b,Point c,Point d){
return (dblcmp(det(b-a,c-a))^dblcmp(det(b-a,d-a)))==-2&&
(dblcmp(det(d-c,a-c))^dblcmp(det(d-c,b-c)))==-2;
}
struct Segment{
Point p1,p2;
Segment(){}
Segment(Point pp1,Point pp2):p1(pp1),p2(pp2){}
bool intersection(Segment s){
return cross(p1,p2,s.p1,s.p2);
}
};
int n,m,cas;
Segment partion[MAXN];
Point endp;
int counte[MAXN];
void counter(Point p){
int l=0,r=n,mid;
while(l<r){
mid=l+(r-l)/2;
if(partion[mid].intersection(Segment(p,endp))) r=mid;
else l=mid+1;
}
++counte[l];
}
void output(){
if(cas++) putchar('\n');
for(int i=0;i<=n;++i){
printf("%d: %d\n",i,counte[i]);
}
}
int main(){
cas=0;
while(scanf("%d",&n),n){
memset(counte,0,sizeof counte);
double x,y,x1,y1,x2,y2,U,L;
scanf("%d %lf %lf %lf %lf",&m,&x1,&y1,&x2,&y2);
for(int i=0;i<n;++i){
scanf("%lf %lf",&U,&L);
partion[i]=Segment(Point(U,y1),Point(L,y2));
}
partion[n]=Segment(Point(x2,y2),Point(x2,y1));
endp=Point(x2+1,(y1+y2)/2.0);
for(int i=0;i<m;++i){
scanf("%lf %lf",&x,&y);
counter(Point(x,y));
}
output();
}
return 0;
}