题目链接:点击打开链接
题意:把一个箱子用挡板分成很多部分,给出挡板的位置和一些点的位置,问每个区间里都有多少点。
因为本题条件说给出的点的y值一定在箱子以内,需要考虑的就是x值。
保存n+2条直线(包括箱子最左和最右边界的两条),每次只需判断点和相邻两直线的位置关系是否一致(即是否在一侧),方法就是算叉积,两个叉积如果异号就表示在这个区域内,如果都小于0答案区间就在右边,大于0在左边
基于这一点可以2分搜索区间。
输入会爆int要用long long。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
long long res[5010];
struct point{
long long x,y;
point(){}
point(long long x,long long y):x(x),y(y){}
point operator -(point obj){
return point(x-obj.x,y-obj.y);
}
};
struct segment{
point a,b;
}k[5010];
long long Cross(point a,point b){
return a.x*b.y-a.y*b.x;
}
int bs(int len,point t){
int l=0,r=len;
while(l<r){
int mid=(l+r)>>1;
long long t1=Cross(t-k[mid].a,k[mid].b-k[mid].a);
long long t2=Cross(t-k[mid+1].a,k[mid+1].b-k[mid+1].a);
if(t1*t2<0) return mid;
else if(t1>0) r=mid-1;
else l=mid+1;
}
return l;
}
int main(){
bool flag=0;
int n,m;
long long mx1,my1,mx2,my2;
while(~scanf("%d",&n),n){
if(!flag) flag=1;
else printf("\n");
scanf("%d%I64d%I64d%I64d%I64d",&m,&mx1,&my1,&mx2,&my2);
memset(res,0,sizeof(res));
int len=0;
k[len].a=point(mx1,my1);
k[len++].b=point(mx1,my2);
for(int i=1;i<=n;i++){
long long x1,x2;
scanf("%I64d%I64d",&x1,&x2);
k[len].a=point(x1,my1);
k[len++].b=point(x2,my2);
}
k[len].a=point(mx2,my1);
k[len].a=point(mx2,my2);
for(int i=1;i<=m;i++){
long long x,y;
scanf("%I64d%I64d",&x,&y);
point t=point(x,y);
int ans=bs(len-1,t);
res[ans]++;
}
for(int i=0;i<=n;i++){
printf("%d: %d\n",i,res[i]);
}
}
return 0;
}