http://acm.hdu.edu.cn/showproblem.php?pid=5033
平面上有n个建筑,每个建筑由 (xi,hi) 表示,m组询问在某一个点能看到天空的视角范围大小。
维护一个凸包,据说可以用单调栈
#include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <set> #include <map> #include <iostream> #include <algorithm> using namespace std; #define RD(x) scanf("%d",&x) #define RD2(x,y) scanf("%d%d",&x,&y) #define clr0(x) memset(x,0,sizeof(x)) typedef long long LL; const double pi = acos(-1.0); const int INF = 2000000007; map <double,int> hash; struct node{ double x,h; }s[100005]; int n,ll[100005],rr[100005]; double ans; set <double> st; bool cmp(node a,node b) { return a.x < b.x; } int main(){ int _,q,cas = 1; RD(_); while(_--){ printf("Case #%d:\n",cas++); RD(n); st.clear(); hash.clear(); for(int i = 1;i <= n;++i){ scanf("%lf%lf",&s[i].x,&s[i].h); ll[i] = rr[i] = i; st.insert(s[i].x); } sort(s+1,s+n+1,cmp); for(int i = 1;i <= n;++i){ hash[s[i].x] = i; for(int j = i - 1;j >= 1;--j){ if(s[j].h > s[i].h){ ll[i] = j; break; } if(j == ll[j]) break; } } for(int i = n;i >= 1;--i){ for(int j = i + 1;j <= n;++j){ if(s[j].h > s[i].h){ rr[i] = j; break; } if(j == rr[j]) break; } } RD(q); while(q--){ double x; scanf("%lf",&x); int r = hash[*st.lower_bound(x)],l = r - 1; double bst = s[r].h/fabs(s[r].x - x); while(r != rr[r]){ r = rr[r]; if(s[r].h > bst*(s[r].x-x)) bst = s[r].h/(s[r].x-x); } ans = pi - atan(bst); bst = s[l].h/fabs(x - s[l].x); while(l != ll[l]){ l = ll[l]; if(s[l].h > bst*(x-s[l].x)) bst = s[l].h/(x-s[l].x); } ans -= atan(bst); printf("%.9lf\n",180.0*ans/pi); } } return 0; }