题目:
在横轴上,给出 n 栋楼(只有高度没有宽度)的位置和高度,再给出m个人的位置,问每个人看天空最大的角度是多少。
分析:
用单调栈+离线查询。
首先可以确定,能影响视野的不一定是两侧最高的楼。确定了这点之后,需要搞清楚什么情况下影响视野的不是最高楼。
只有这样的情况下,右边的人往左看的时候有可能是低楼影响视野。所以我们用单调栈维护一个高度递减但是相邻点斜率绝对值递增的集合,对于这些点右边的人,只有集合中这些点会影响视野,根据人的位置不同,不同的点影响视野。从左到右依次建立,遇到人了就查询一下,然后继续构建,再去遇见下一个人。就可以求出所有人左边最大视野。同理右边再来一遍。
代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN=2e5+5;
const double EPS=1e-8;
const int INF=0x3f3f3f3f;
const int MOD = 1e9+7;
const double PI = acos(-1.0);
struct Build {
Build() {
memset(ang, 0, sizeof(ang));
}
double x, h;
double ang[2];
bool pos;
int id;
}b[MAXN];
int n,m,sta[MAXN];
bool cmp1(Build a,Build b){
return a.x < b.x;
}
bool cmp2(Build a,Build b){
return a.id < b.id;
}
double deal(Build a,Build b){
double dx = fabs(a.x - b.x);
double dy = fabs(a.h - b.h);
return dy / dx;
}
int main(){
int T,kase = 1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lf%lf",&b[i].x,&b[i].h);
b[i].pos = false;
b[i].id = i;
}
scanf("%d",&m);
for(int i=n;i<n+m;i++){
scanf("%lf",&b[i].x);
b[i].h = 0;
b[i].pos = true;
b[i].id = i;
}
n += m;
sort(b,b+n,cmp1);
int top = 0;
for(int i=0;i<n;i++){
if(b[i].pos == false){
while(top && b[sta[top]].h <= b[i].h) top--;
while(top >= 2 && deal(b[sta[top-1]],b[sta[top]]) > deal(b[sta[top]],b[i]) ) top--;
sta[++top] = i;
}else{
while(top >= 2 && deal(b[sta[top-1]],b[sta[top]]) > deal(b[sta[top]],b[i])) top--;
if(top == 0){
b[i].ang[0] = 0;
}else{
b[i].ang[0] = deal(b[sta[top]],b[i]);
}
}
}
top = 0;
for(int i=n-1;i>=0;i--){
if(b[i].pos == false){
while(top && b[sta[top]].h <= b[i].h) top--;
while(top >= 2 && deal(b[sta[top-1]],b[sta[top]]) > deal(b[sta[top]],b[i])) top--;
sta[++top] = i;
}else{
while(top >= 2 && deal(b[sta[top-1]],b[sta[top]]) > deal(b[sta[top]],b[i])) top--;
if(top == 0){
b[i].ang[1] = 0;
}else{
b[i].ang[1] = deal(b[sta[top]],b[i]);
}
}
}
sort(b,b+n,cmp2);
printf("Case #%d:\n",kase++);
for(int i=0;i<n;i++){
if(b[i].pos == true){
double ans = PI - atan(b[i].ang[0]) - atan(b[i].ang[1]);
ans = ans / PI * 180;
printf("%.10lf\n",ans);
}
}
}
return 0;
}