题意:
地面上有n座楼 你分别站在m个位置上 问每个位置上能看见多大角度的天空
思路:
很明显能想到在站的位置两边维持单调性 因此我们可以将站位和楼的位置排序 从左到右维护一遍 再从右到左维护一遍 这里可以利用单调栈 对于新扫描到的位置 如果是楼 那么栈中比它矮的楼就没用了可以出栈 如果是站位 可以这样判断 如果可以看见栈底的楼(最高的楼)那么前面的矮楼一定不会影响后面了 可以出栈
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cassert> #include<vector> #include<set> #include<map> #include<queue> using namespace std; #define N 100010 #define PI acos(-1) struct node { int id; double x, h; bool operator<(const node ff) const { return x < ff.x; } } nd[N * 2], st[N]; double ansl[N], ansr[N]; int n, m, t, T, tot, top; int main() { int i, j, id; double fh, fx, dx, k; scanf("%d", &T); for (t = 1; t <= T; t++) { tot = 0; scanf("%d", &n); for (i = 1; i <= n; i++) { scanf("%lf%lf", &fx, &fh); nd[tot].id = 0; nd[tot].x = fx; nd[tot].h = fh; tot++; } scanf("%d", &m); for (i = 1; i <= m; i++) { scanf("%lf", &fx); nd[tot].id = i; nd[tot].x = fx; tot++; ansl[i] = ansr[i] = 0; } sort(nd, nd + tot); //L top = 0; for (i = 0; i < tot; i++) { if (nd[i].id) { id = nd[i].id; dx = nd[i].x; fh = st[0].h; fx = st[0].x; while (top > 1 && fh / (dx - fx) >= st[top - 1].h / (dx - st[top - 1].x)) top--; for (j = 0; j < top; j++) { k = st[j].h / (dx - st[j].x); if (ansl[id] < k) ansl[id] = k; } } else { while (top && nd[i].h >= st[top - 1].h) top--; st[top++] = nd[i]; } } //R top = 0; for (i = tot - 1; i >= 0; i--) { if (nd[i].id) { id = nd[i].id; dx = nd[i].x; fh = st[0].h; fx = st[0].x; while (top > 1 && fh / (fx - dx) >= st[top - 1].h / (st[top - 1].x - dx)) top--; for (j = 0; j < top; j++) { k = st[j].h / (st[j].x - dx); if (ansr[id] < k) ansr[id] = k; } } else { while (top && nd[i].h >= st[top - 1].h) top--; st[top++] = nd[i]; } } printf("Case #%d:\n", t); for (i = 1; i <= m; i++) { printf("%f\n", 180.0 - (atan(ansl[i]) + atan(ansr[i])) / PI * 180); } } return 0; }
原文地址:http://blog.csdn.net/houserabbit/article/details/39520055