poj 2318 TOYS(判断点在多边形内+二分查找)

题目链接:点击打开链接


题意:把一个箱子用挡板分成很多部分,给出挡板的位置和一些点的位置,问每个区间里都有多少点。


因为本题条件说给出的点的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;
}







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值