题意:给了好多楼房的高度和位置,然后问一个人在一个位置,它可以看到的左右天空的角度
思路:用单调栈维护一个它能看到的最高的位置,然后反过来再求一遍,两遍的和就是结果了
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=400010;
inline int getint(){
int res=0;
char c=getchar();
bool mi=false;
while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
return mi ? -res : res;
}
struct edge{
int x,y,id;
}num[maxn],stack1[maxn];
bool cmp(const edge &a,const edge &b){return a.x<b.x;}
double ans[maxn];
int calc(edge a,edge b,edge c){
ll aa=(ll)(abs)(a.y-c.y)*abs(c.x-b.x);
ll bb=(ll)(abs)(b.y-c.y)*abs(c.x-a.x);
return aa>=bb;
}
double angle(edge a,edge b){
return atan((double)(abs)(b.x-a.x)/(double)(a.y));
}
int main(){
int T,n,cas=1,q;
scanf("%d",&T);
while(T--){
n=getint();
for(int i=0;i<n;i++) num[i].x=getint(),num[i].y=getint(),num[i].id=0;
q=getint();
for(int i=0;i<q;i++) num[n+i].x=getint(),num[n+i].y=0,num[n+i].id=i+1;
sort(num,num+n+q,cmp);
memset(ans,0,sizeof(ans));
int len=0;
for(int i=0;i<n+q;i++){
if(num[i].id!=0){
while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
ans[num[i].id]+=angle(stack1[len-1],num[i]);
}else{
while(len&&stack1[len-1].y<=num[i].y) len--;
while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
stack1[len++]=num[i];
}
}
len=0;
for(int i=n+q-1;i>=0;i--){
if(num[i].id!=0){
while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
ans[num[i].id]+=angle(stack1[len-1],num[i]);
}else{
while(len&&stack1[len-1].y<=num[i].y) len--;
while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
stack1[len++]=num[i];
}
}
printf("Case #%d:\n",cas++);
for(int i=1;i<=q;i++) printf("%.10lf\n",ans[i]*180/PI);
}
return 0;
}