博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/39494433
题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度,给出一个X坐标,高度为0,问X位置能看到的视角是多少度。如图:
图一:
图二:
图一为样例一,图二为样例三,红色部分为高楼,蓝色虚线为视角的最大范围。
解题思路:
由于有10w个点跟10w次询问,所以朴素的算法判断肯定会超时的。所以就需要用单调栈,维护相邻两建筑顶(xi,hi)的连线的斜率的绝对值上升的单调栈。
如图的单调栈存的大致走向
这样就可以做到O(n+m)的复杂度,再加上一个排序,也只有O((n+m)*log(n+m))的复杂度,就是完全可以接受的了。
具体的见代码部分:
#include <stdio.h> #include <stack> #include <math.h> #include <algorithm> using namespace std; const double eps = 1e-8; const double Pi = acos(-1.0); struct Point { double x, y; int id; } P[200005], Q[200005], L[200005], R[200005]; int dcmp(double x) { return x <-eps ? -1 : x > eps; } int cmp(Point a, Point b) { return a.x < b.x; } double xmult(Point a, Point b, Point c) { return (a.x-c.x)*(b.y-c.y) - (a.y-c.y)*(b.x-c.x); } double ans[200005]; int main() { int n, m; int T, icase = 1; scanf("%d", &T); while(T--) { scanf("%d", &n); for(int i = 0; i < n; ++i) { scanf("%lf%lf", &P[i].x, &P[i].y); P[i].id = -1; } scanf("%d", &m); for(int i = n; i < m+n; ++i) { scanf("%lf", &P[i].x); P[i].y = 0; P[i].id = i-n; } sort(P, P+n+m, cmp); int it = 0; for(int i = 0; i < n+m; ++i) { while(it >= 2 && dcmp(xmult(Q[it-1], Q[it-2], P[i])) <= 0) --it; if(it) L[i] = Q[it-1]; Q[it++] = P[i]; } it = 0; for(int i = n+m-1; i >= 0; --i) { while(it >= 2 && dcmp(xmult(Q[it-1], Q[it-2], P[i])) >= 0) --it; if(it) R[i] = Q[it-1]; Q[it++] = P[i]; } for(int i = 0; i < n; ++i) { if(P[i].id != -1) { ans[P[i].id] = atan((P[i].x-L[i].x)/L[i].y); ans[P[i].id] += atan((R[i].x-P[i].x)/R[i].y); ans[P[i].id] /= (Pi/180); } } printf("Case #%d:\n", icase++); for(int i = 0; i < m; ++i) { printf("%.16lf\n", ans[i]); } } return 0; }
时间: 2024-11-03 03:42:15