poj-2318 TOYS

75 篇文章 0 订阅
30 篇文章 0 订阅

题意:

给出平面上一个矩形和n个纵向分割矩形的直线;

直线之间互不相交,将矩形分割为n-1个块;

现在矩形上有m个点,求每个块内有几个点;

n,m<=5000,数据保证点严格在块的内部(不在直线上);


题解:

首先将直线求出来,然后最朴素的想法是拿一个点一一和块去比较;

这样复杂度是O(nm)的,并且实际上做了许多无用的计算;

例如:当你用一个点去比较一个块之后,实际上已经可以知道这个点是在块的左面还是右面了;

也就是说每次比较就可以去掉一半的块,即二分求解;

由于左右对称,所以我们只需要判断点是否在块右边界的左面;

这个满足二分性质,用叉积来判断之后,可以O(logn)求解;

总体复杂度O(mlogn);


代码:


#include<math.h>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 5100
using namespace std;
const double EPS=1e-6;
const double INF=1e100;
struct Point
{
	double x,y;
	friend Point operator -(Point a,Point b)
	{
		Point temp;
		temp.x=a.x-b.x,temp.y=a.y-b.y;
		return temp;
	}
	friend Point operator +(Point a,Point b)
	{
		Point temp;
		temp.x=a.x+b.x,temp.y=a.y+b.y;
		return temp;
	}
	friend Point operator *(double a,Point b)
	{
		Point temp;
		temp.x=a*b.x,temp.y=a*b.y;
		return temp;
	}
	friend double operator ^(Point a,Point b)
	{
		return a.x*b.y-a.y*b.x;
	}
}st,en;
struct Line
{
	Point p,v;
	int cnt;
	void Build(double a,double b)
	{
		p=st;
		Point u=en;
		p.x=a;
		u.x=b;
		v=u-p;
	}
	bool check(Point t)
	{
		if((v^(t-p))>0)
			return 1;
		else
			return 0;
	}
}li[N];
int main()
{
	int n,m,i,j,k,l,r,mid;
	double a,b;
	Point t;
	while(scanf("%d",&n)&&n)
	{
		memset(li,0,sizeof(li));
		scanf("%d",&m);
		scanf("%lf%lf%lf%lf",&st.x,&en.y,&en.x,&st.y);
		li[0].Build(st.x,st.x);
		li[n+1].Build(en.x,en.x);
		for(i=1;i<=n;i++)
		{
			scanf("%lf%lf",&a,&b);
			li[i].Build(b,a);
		}
		for(i=1;i<=m;i++)
		{
			scanf("%lf%lf",&t.x,&t.y);
			l=0,r=n+1;
			while(l<=r)
			{
				mid=l+r>>1;
				if(li[mid].check(t))
					r=mid-1;
				else
					l=mid+1;
			}
			li[l].cnt++;
		}
		for(i=1;i<=n+1;i++)
		{
			printf("%d: %d\n",i-1,li[i].cnt);
		}
		putchar('\n');
	}
	return 0;
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值