计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 B Windows 画图
- 44.21%
- 1000ms
- 131072K
在 Windows 的“画图”工具里,可以绘制各种各样的图案。可以把画图当做一个标准的二维平面,在其上先后绘制了 n 条颜色互不相同的线段。
按绘制的时间顺序,从先到后把线段依次编号为 1 到 n。第 i 条线段的两个端点分别为 (xai,yai) 和 (xbi,ybi),线段的粗细忽略不计。后绘制的线段不会改变之前绘制的线段的位置。
请写一个程序,回答 q 组询问,每组询问给出一个坐标 (xi,yi),你需要算出在这个点上最后绘制的线段编号。
输入格式
第一行包含两个正整数 n,m(1≤n≤80000,1≤m≤250),分别表示线段的数目以及坐标的最大取值(下面会具体说明)。
接下来 n 行,每行输入四个正整数 xai,yai,xbi,ybi (1≤xai,yai,xbi,ybi≤m, (xai,yai)≠(xbi,ybi)),依次表示每条线段两个端点的坐标。
接下来一行,输入一个正整数 q(1≤q≤62500),表示询问的组数。
接下来 q 行,每行输入两个正整数 xi,yi(1≤xi,yi≤m),分别表示每组询问的坐标。
输出格式
输出 q 行,每行一个整数,表示该位置最上面(最后绘制)的线段的编号。
若该点上不存在线段,请输出 0。
样例解释
样例对应题目描述中的图。
样例输入
5 8 2 5 5 2 5 2 3 8 8 4 1 4 2 2 5 8 8 7 4 1 4 3 4 5 2 6 4 3 5
样例输出
4 2 5 0
Source
计蒜之道 2017 程序设计大赛 - 计蒜客 复赛 B Windows 画图
My Solution
题意:在一个m*m(1≤n≤80000,1≤m≤250)的平面内给出n条线段,然后给出q(1≤q≤62500)个询问,为点x,y最近被2条线段所经过,如果没有则输出0。
几何、平面、枚举
这里 8e4 * 250 == 2e7,刚好可以预处理出mp[x][y]表示最后一次经过的线段。
然后注意下精度问题即可,可能是向上修复精度,也可能是向下修复精度。
y = -1;
if(fabs(k*(j-xa) + ya*1.0 - double(int(k*(j-xa) + ya*1.0))) < EPS) y = int(k*(j-xa) + ya*1.0);
if(fabs(k*(j-xa) + ya*1.0 - double(int(k*(j-xa) + ya*1.0)) - 1) < EPS) y = int(k*(j-xa) + ya*1.0) + 1;
if(y < miny || y > maxy) continue;
mp[j][y] = i;
时间复杂度 O(n*m)
空间复杂度 O(m*m)
#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
typedef long long LL;
const int MAXN = 80000 + 8, MAXM = 250 + 8;
const double EPS = 1e-6;
int mp[MAXM][MAXM];
int main()
{
#ifdef LOCAL
freopen("b.txt", "r", stdin);
//freopen("b.out", "w", stdout);
int T = 1;
while(T--){
#endif // LOCAL
//ios::sync_with_stdio(false); cin.tie(0);
int n, m, i, j, xa, ya, xb, yb, y, miny, maxy;
double k;
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++){
scanf("%d%d%d%d", &xa, &ya, &xb, &yb);
miny = min(ya, yb), maxy = max(ya, yb);
if(xa > xb) swap(xa, xb), swap(ya, yb);
if(xa == xb){
for(j = miny; j <= maxy; j++){
mp[xa][j] = i;
}
continue;
}
else k = (yb - ya)*1.0/(xb - xa);
for(j = xa; j <= xb; j++){
y = -1;
if(fabs(k*(j-xa) + ya*1.0 - double(int(k*(j-xa) + ya*1.0))) < EPS) y = int(k*(j-xa) + ya*1.0);
if(fabs(k*(j-xa) + ya*1.0 - double(int(k*(j-xa) + ya*1.0)) - 1) < EPS) y = int(k*(j-xa) + ya*1.0) + 1;
if(y < miny || y > maxy) continue;
mp[j][y] = i;
}
}
int q;
scanf("%d", &q);
while(q--){
scanf("%d%d", &xa, &ya);
printf("%d\n", mp[xa][ya]);
}
#ifdef LOCAL
cout << endl;
}
#endif // LOCAL
return 0;
}
Thank you!
------from ProLights