题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5033
问题的意思很是简单。一些高楼N<= 10^5,问一些人Q<=10^5处在高楼之间最大的视野角度。10^5次询问。比较痛苦。
一开始,因为就一简单的计算几何,直接就暴力写了。果断TLE。后来一看数据范围,我就给自己跪了。。这么大是数据量,果断会超时的。。看来还需要继续学习啊!!
后来看了题解,只能说计算几何仍然需要努力学习啊。。!!
很巧妙的一个思路。
离线来搞,把需要询问的点加到高楼里,当做高楼来搞,维护一个半凸包。。看下图:
这样就很好的来求解了。。思路巧妙,代码简单。。
Code:
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
const int N = 1e5 * 2 + 5;
const double eps = 1e-8;
const double pi = acos(-1.0);
struct POINT
{
double x, y;
int id;
POINT() {
id = -1;
}
POINT(double xx, double hh){
x = xx;
y = hh;
id = -1;
}
}p[N], st[N];
int n, q;
double ans[N];
bool cmp(POINT a, POINT b)
{
if(a.x < b.x) return true;
return false;
}
double cross(POINT o, POINT a, POINT b)
{
return (a.x - o.x) * (b.y - o.y) - (a.y - o.y) * (b.x - o.x);
}
void solve()
{
int top = 0;
st[top ++] = p[1];
st[top ++] = p[2];
if(p[2].y == 0){// special judge if second point is the person's position..
ans[p[2].id] += atan(p[1].y / (p[2].x - p[1].x));
}
for(int i = 3; i < n; i ++){
while(top >= 2 && cross(st[top - 1], p[i], st[top - 2]) > eps) top --;
st[top ++] = p[i];
if(p[i].y == 0.0){
ans[p[i].id] += atan(st[top - 2].y / (st[top - 1].x - st[top - 2].x));
}
}
}
void reverse()
{
for(int i = 1; i <= n; i ++){
p[i].x = 1e8 * 1.0 - p[i].x;
}
}
void Init()
{
for(int i = 1; i <= q; i ++){
ans[i] = 0.0;
}
}
int main()
{
// freopen("1.txt", "r", stdin);
int T, k = 0;
scanf("%d", &T);
while(T --){
scanf("%d", &n);
for(int i = 1; i <= n; i ++){
scanf("%lf %lf", &p[i].x, &p[i].y);
}
scanf("%d", &q);
Init();
double x;
for(int i = 1; i <= q; i ++){
scanf("%lf", &x);
p[i + n].x = x; p[i + n].y = 0.0;
p[i + n].id = i;
}
n = n + q;
sort(p + 1, p + 1 + n, cmp);
solve();
reverse();
sort(p + 1, p + 1 + n, cmp);
solve();
printf("Case #%d:\n", ++ k);
for(int i = 1; i <= q; i ++){
printf("%.10lf\n", 180.0 - ans[i] / pi * 180.0);
}
}
return 0;
}