题目概述
有一长方形,左上顶点坐标(x1,y1),右下顶点坐标(x2,y2),被N条上端点为(up,y1),下端点为(low,y2)的线段分成N+1部分,向长方形中扔M个质点,每个点坐标(x,y),求落在每一部分的点的数量
时限
2000ms/6000ms
输入
每组数据第一行6个整数N,M,x1,y1,x2,y2,其后N行,每行2个整数up,low,再其后M行,每行2个整数x,y,输入到N=0结束
限制
1<=N<=5000;1<=M<=5000;所有线段互不相交;所有质点不会落在线段上;所有质点不会落在长方形外面,但落会落在边界上,也视为落在内部;所有线段按从左到右呈现在输入中
输出
每组输出共N+1行,每行格式为
#: @
#代表长方形的分块序号,从0开始到N结束,@代表该分块中的质点数,冒号后有一空格,两组输出之间有一个空行
样例输入
5 6 0 10 60 0
3 1
4 3
6 8
10 10
15 30
1 5
2 1
2 8
5 5
40 10
7 9
4 10 0 10 100 0
20 20
40 40
60 60
80 80
5 10
15 10
25 10
35 10
45 10
55 10
65 10
75 10
85 10
95 10
0
样例输出
0: 2
1: 1
2: 1
3: 1
4: 0
5: 1
0: 2
1: 2
2: 2
3: 2
4: 2
讨论
计算几何,基本的点线位置关系,搭配二分能够快不少,只是不知为何必须按点线位置关系二分而不能单纯按点的横坐标和线段端点的在一条边上的横坐标二分,如此样例都能过,但会WA
题解状态
220K,63MS,C++,1037B
题解代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 5010
#define memset0(a) memset(a,0,sizeof(a))
int N, M;//隔板数 质点数
int up[MAXN], low[MAXN], cnt[MAXN];//上边界 下边界 每块内质点数
bool f;//控制空行输出
inline int xp(int x1, int y1, int x2, int y2, int x3, int y3)//cross_product 向量积 以第2个点为公共起点 指向第1,3个点 然后前者构成的向量叉乘后者
{
return (x1 - x2)*(y3 - y2) - (y1 - y2)*(x3 - x2);
}
void fun(int x1, int y1, int x2, int y2)
{
for (int p = 1; p <= N; p++)
scanf("%d%d", &up[p], &low[p]);//input//视左边界为第一块隔板
up[N + 1] = low[N + 1] = x2;//右边界为最后一块隔板
for (int p = 0; p < M; p++) {
int x, y;
scanf("%d%d", &x, &y);//input
int l = 0, r = N + 1, m = (l + r) / 2;//下面是二分过程
while (r - l > 1) {
if (xp(x, y, low[m], y2, up[m], y1) > 0)
l = m;
else
r = m;
m = (l + r) / 2;
}
cnt[m]++;
}
if (f)
printf("\n");//output
for (int p = 0; p <= N; p++)
printf("%d: %d\n", p, cnt[p]);//output
f = 1;//输出间空行
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
int x1, y1, x2, y2;//长方形左上和右下点坐标
while (~scanf("%d%d%d%d%d%d", &N, &M, &x1, &y1, &x2, &y2) && N) {//input
fun(x1, y1, x2, y2);
memset0(cnt);
}
}
EOF