POJ 2318 TOYS | 二分+判断点在多边形内

题意:

给一个矩形的区域(左上角为(x1,y1) 右下角为(x2,y2)),给出n对(u,v)表示(u,y1) 和 (v,y2)构成线段将矩形切割

这样构成了n+1个多边形,再给出m个点,问每个多边形内有多少个点.

读入为n,m,x1,y1,x2,y2

n个数对(u,v),m个数对(x,y) (n,m<=5000)


 

题解:

很暴力的想法是对于每个点,枚举每个多边形进行检查.

但是多组数据就很江

考虑一下判断点在多边形内的射线法可知

枚举一个多边形的时候就可以知道点在多边形的左边还是右边

这样我们对每个点二分一下他属于那个多边形,依靠上述性质就可以在nlogn时间内做完

#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
#define N 5010
using namespace std;
int  n,m,x1,x2,y1,y2,up[N],down[N],cnt[N],t;
struct point
{
    int x,y;
    point (){} ;
    point (int _x,int _y) :
	x(_x),y(_y) {};
    bool operator < (const point &rhs) const
	{
	    if (x==rhs.x) return y<rhs.y;
	    return x<rhs.x;
	}
    inline int operator * (const point &rhs) const
	{
	    return x*rhs.y-y*rhs.x;
	}
    inline point operator - (const point &rhs) const
	{
	    return point(x-rhs.x,y-rhs.y);
	}
    friend inline int dot (const point &lhs,const point &rhs)
	{
	    return lhs.x*rhs.x+lhs.y*rhs.y; 
	}
}toy[N];
bool isinline (const point &p1,const point &p2,const point &p3)
{
    int det=(p1-p3)*(p2-p3);
    if (det!=0) return 0;
    int Dot=dot(p1-p3,p2-p3);
    return Dot<=0;
}
struct polygon
{
    point p[10];
    int inner (const point &pp)
	{
	    int cnt=0;
	    for (int i=1;i<=4;i++)
	    {
		if (isinline(p[i],p[i+1],pp)) return 1;
		int d1=p[i].y-pp.y,d2=p[i+1].y-pp.y;
		int del=(p[i]-pp)*(p[i+1]-pp);
		if ( (del>=0 && d1>=0 && d2<0) ||
		     (del<=0 && d1<0 && d2>=0) ) cnt++;
	    }
	    return cnt;
	}
}pol[N];
void solve()
{
    sort(toy+1,toy+1+m);
    memset(cnt,0,sizeof(cnt));
    for (int i=0;i<=n;i++)
    {
	pol[i].p[1]=pol[i].p[5]=point(up[i],y1);
	pol[i].p[4]=point(down[i],y2);
	pol[i].p[3]=point(down[i+1],y2);
	pol[i].p[2]=point(up[i+1],y1);
    }
    for (int i=1;i<=m;i++)
    {
	int l=0,r=n,mid;
	while (l<=r)
	{
	    mid=l+r>>1;
	    int res=pol[mid].inner(toy[i]);
	    if (res&1)
	    {
		cnt[mid]++;
		break;
	    }
	    if (res>0) l=mid+1;
	    else r=mid;
	}
    }
}
int main()
{
    while (scanf("%d",&n),n)
    {
	if (++t!=1) puts("");
	scanf("%d%d%d%d%d",&m,&x1,&y1,&x2,&y2);
	for (int i=1;i<=n;i++)
	    scanf("%d%d",&up[i],&down[i]);
	for (int i=1,x,y;i<=m;i++)
	{
	    scanf("%d%d",&x,&y);
	    toy[i]=point(x,y);
	}
	up[0]=down[0]=x1,up[n+1]=down[n+1]=x2;
	solve();
	for (int i=0;i<=n;i++)
	    printf("%d: %d\n",i,cnt[i]);
    }
    return 0;
}

 

posted @ 2017-12-07 18:20  MSPqwq  阅读(169)  评论(0编辑  收藏  举报