题目链接:点击打开链接
题意:把一个箱子用挡板分成很多部分,给出挡板的位置和一些点的位置,问每个区间里都有多少点。
因为本题条件说给出的点的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; }