题目地址:
http://acm.hdu.edu.cn/showproblem.php?pid=5033
题意:
一排N个房子,各有位置和高度,Q次询问,问小明再某一位置能看到的天空角度。(小明高度近似为0,保证小明和房子不重合)
必要思考:
1.首先前边比房子 i 矮的房子一定看不见。可能被看到的房子一定是高度递减的。
2.递减的过程中如果是下凹的递减也一定看不见,也就是需要时相邻两点的斜率是递增的。
3.所用用单调栈来维护高度递减,相邻房子连线斜率递增的房子。
4.离线处理,如果高度为0,就视为人,人不必入栈,栈顶元素为边界,左右个跑一次。
代码:
#include<bits/stdc++.h> using namespace std; struct node { double po; double h; int id; }; double ans[100005]; const double pi=acos(-1.0); vector<node> data; bool cmp(const node &a,const node &b) { return a.po<b.po; } int s[100005]; void solve() { int top=0; for(int i=0;i<data.size();i++) { if(!top){ s[++top]=i; continue; } while(top&&data[s[top]].h<=data[i].h) top--; while(top>=2&&fabs(data[s[top-1]].h-data[s[top]].h)*fabs(data[s[top]].po-data[i].po)>=fabs(data[i].h-data[s[top]].h)*fabs(data[s[top]].po-data[s[top-1]].po)) top--; if(data[i].h==0) { ans[data[i].id]-=atan(data[s[top]].h/fabs(data[s[top]].po-data[i].po)); } else s[++top]=i; } } int main() { int T;scanf("%d",&T); int Case=0; while(T--) { data.clear(); double po,h;node a; printf("Case #%d:\n",++Case); int n;scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%lf%lf",&a.po,&a.h); data.push_back(a); } int m;scanf("%d",&m); for(int i=1;i<=m;i++) { scanf("%lf",&a.po); a.h=0;a.id=i; data.push_back(a); ans[i]=pi; } sort(data.begin(),data.end(),cmp); solve(); reverse(data.begin(),data.end()); solve(); for(int i=1;i<=m;i++) { printf("%.10f\n",ans[i]*180/pi); } } }
浙公网安备 33010602011771号