题意:一个城市在X轴上,有很多高大的建筑,人站在城市中,问能看到天的角度是多少
思路:从左往右维护一个单调栈,记录当前可以看到的最高的一个建筑。每到一个人的位置就能直接算。然后从右往左再来一遍
参考:http://blog.csdn.net/u011345136/article/details/39454537
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const double pi=acos(-1);
struct building
{
double x;
int h;
};
bool operator < (const building &a,const building &b)
{
return a.x<b.x;
}
int n;
building b[200005];
int s[200005];
int head=0;
double ans[100005];
bool check(building a,building b,building c)
{
if(c.h<0)
{
c.h=0;
}
return abs(a.h-c.h)*abs(c.x-b.x)>=abs(b.h-c.h)*abs(c.x-a.x);
}
int main()
{
//freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
int kase=0;
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;++i)
{
scanf("%lf%d",&b[i].x,&b[i].h);
}
int q;
scanf("%d",&q);
for(int i=0;i<q;++i)
{
scanf("%lf",&b[i+n].x);
b[n+i].h=-i;
}
sort(b,b+n+q);
// for(int i=0;i<n+q;++i)
// {
// cout<<b[i].x<<' '<<b[i].h<<endl;
// }
head=0;
// cout<<"zzzzzzzzzzzzzzzzzzzzzzzzz"<<endl;
// cout<<n<<' '<<q<<endl;
for(int i=0;i<n+q;++i)
{
if(b[i].h<=0)
{
// cout<<head<<endl;
while(head>1&&check(b[s[head-2]],b[s[head-1]],b[i]))
{
head--;
}
ans[-b[i].h]=atan(b[s[head-1]].h/(b[i].x-b[s[head-1]].x));
}
else
{
// cout<<"??"<<head<<endl;
while(head>0&&b[s[head-1]].h<b[i].h)head--;
while(head>1&&check(b[s[head-2]],b[s[head-1]],b[i]))
{
head--;
}
s[head++]=i;
}
}
head=0;
for(int i=n+q-1;i>=0;--i)
{
if(b[i].h<=0)
{
while(head>1&&check(b[s[head-2]],b[s[head-1]],b[i]))
{
head--;
}
// cout<<b[s[head-1]].h<<' '<<(b[i].x-b[s[head-1]].x)<<endl;
ans[-b[i].h]+=atan(b[s[head-1]].h/(b[s[head-1]].x-b[i].x));
}
else
{
while(head>0&&b[s[head-1]].h<b[i].h)head--;
while(head>1&&check(b[s[head-2]],b[s[head-1]],b[i]))
{
head--;
}
s[head++]=i;
}
}
// cout<<ans[0]<<endl;
printf("Case #%d:\n",++kase);
printf("%.5lf\n",(pi-ans[0])*180/pi);
for(int i=1;i<q;++i)
{
printf("%.5lf\n",(pi-ans[i])*180/pi);
}
// puts("");
}
return 0;
}