http://acm.hdu.edu.cn/showproblem.php?pid=5033
Building Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 303 Accepted Submission(s): 85 Special Judge
3 3 1 2 2 1 5 1 1 4 3 1 3 2 2 5 1 1 4 3 1 4 2 3 5 1 1 4
Case #1: 101.3099324740 Case #2: 90.0000000000 Case #3: 78.6900675260
题意:
给出N幢摩天大楼的位置和高度,有Q次查询,问在某点处能看见天空的角度范围。
分析:
一开始的想法是维护一个单调栈,首先离线数据并排序排序,然后左右扫两边。单调栈内大楼的高度要递减,然后判断栈顶元素是否比它的前一个更优,如果不是则出栈。但是如果栈顶元素比它前一个优,并不能保证是全局最优的。
正确的维护方法是保证单调栈内的大楼高度递减,而且要使得这些大楼的最高点构成一个类似凸包的形状,或者说是凸包的一部分,然后再判断栈顶元素和它前一个比是否更优,如果不是则出栈。这样最后的栈顶元素就是待查询点在某方向的视角最大范围,记录下这个方向向量即可,最后角度只要求两向量间的夹角即可。
(ugly code,maybe I could attend ioccc)
/*
*
* Author : fcbruce
*
* Date : 2014-09-21 13:07:59
*
*/
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10
#ifdef _WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define maxm 100010
#define maxn 100010
using namespace std;
struct node
{
double x,h;
bool operator < (const node &n)const
{
return x<n.x;
}
}sky[maxn];
struct __q
{
double x;
int h;
bool operator < (const __q &q)const
{
return x<q.x;
}
}q[maxm];
inline double
dot(const pair<double,double> &v1,const pair<double,double> &v2)
{
return v1.first*v2.first+v1.second*v2.second;
}
inline double
len(const pair<double,double> &v)
{
return sqrt(sqr(v.first)+sqr(v.second));
}
pair<double,double> v_l[maxn],v_r[maxn];
int st[maxn];
int
main()
{
#ifdef FCBRUCE
freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE
int T_T,__=0;
scanf("%d",&T_T);
while (T_T--)
{
int n,m;
scanf("%d",&n);
for (int i=0;i<n;i++)
scanf("%lf%lf",&sky[i].x,&sky[i].h);
sort(sky,sky+n);
scanf("%d",&m);
for (int i=0;i<m;i++)
{
scanf("%lf",&q[i].x);
q[i].h=i;
}
sort(q,q+m);
for (int i=0,j=0,top=-1;i<m;i++)
{
while (j<n && sky[j].x<q[i].x)
{
while (top>-1 && sky[j].h>sky[st[top]].h-eps) top--;
while (top>0 && (sky[st[top]].h-sky[j].h)*(sky[st[top]].x-sky[st[top-1]].x)<
(sky[st[top-1]].h-sky[st[top]].h)*(sky[j].x-sky[st[top]].x)+eps) top--;
st[++top]=j++;
while (top>0 && sky[st[top]].h*(q[i].x-sky[st[top-1]].x)<sky[st[top-1]].h*(q[i].x-sky[st[top]].x)+eps) top--;
}
while (top>0 && sky[st[top]].h*(q[i].x-sky[st[top-1]].x)<sky[st[top-1]].h*(q[i].x-sky[st[top]].x)+eps) top--;
v_l[q[i].h]=make_pair(sky[st[top]].x-q[i].x,sky[st[top]].h);
}
for (int i=m-1,j=n-1,top=-1;i>=0;i--)
{
while (j>=0 && sky[j].x>q[i].x)
{
while (top>-1 && sky[j].h>sky[st[top]].h-eps) top--;
while (top>0 && (sky[st[top]].h-sky[j].h)*(sky[st[top-1]].x-sky[st[top]].x)<
(sky[st[top-1]].h-sky[st[top]].h)*(sky[st[top]].x-sky[j].x)+eps) top--;
st[++top]=j--;
while (top>0 && sky[st[top]].h*(sky[st[top-1]].x-q[i].x)<sky[st[top-1]].h*(sky[st[top]].x-q[i].x)+eps) top--;
}
while (top>0 && sky[st[top]].h*(sky[st[top-1]].x-q[i].x)<sky[st[top-1]].h*(sky[st[top]].x-q[i].x)+eps) top--;
v_r[q[i].h]=make_pair(sky[st[top]].x-q[i].x,sky[st[top]].h);
}
printf("Case #%d:\n",++__);
for (int i=0;i<m;i++)
printf("%.10f\n",acos(dot(v_l[i],v_r[i])/(len(v_r[i])*len(v_l[i])))*180/PI);
}
return 0;
}
原文地址:http://blog.csdn.net/u012965890/article/details/39456117