您的位置:首页 > 产品设计 > UI/UE

HDU 5033 Building

2015-09-09 15:56 549 查看
题目大意:给出n个高楼的位置(可看做垂直x轴的线段) 有q次查询 每次查询一个x坐标 求在此处的能看到天空的角度范围

由于查询次数q有10的5次方 n也有10的5次方 x坐标10的7次方 很难想到预先处理好 然后O(1)查询的处理方式 所以可以尝试用离线 预先把查询的坐标 以(x,0)存入 高楼以(x,h)来存

首先要以x排个序 首先 如果你每个查询点 左右的暴力找 这样肯定太慢 但你不难发现一条规律 每个点在右面找到的那个斜率最高点设为A(即从查询点来看 这个大楼是最高的)那么这个点有什么特征的 首先 很容易的推出 点A 右面比A低的肯定不行 同理A左面(和查询点之间)也不存在比A高的 当然这样还是不够的 因为极限数据 最高复杂度依然会T 所以我们继续推 A和查询点直接的点 应该是构成一条 x²一样曲线的(其实是折线) 这样才能做到在A点斜率最大 而A右面的点应该是 根号x曲线 一样的 这样 不难得到
A是一个凸包上的点 (如果这都没想到凸包 说明你没透彻理解凸包) 查询点加进来之后(从右往左扫时) A和查询点之间的点会被删掉 所以我们扫到每个查询点时 和凸包上的上一个点 计算一下即可 从左到右扫两遍 复杂度O(nlogn)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#define scnaf scanf
#define cahr char
#define bug puts("bugbugbug");
using namespace std;
typedef long long ll;
const int mod=1000000007;
const int maxn=2e5+500;
const int inf=1e9+10000;
#define pai acos(-1.0)
double ans[maxn];
int n;
struct Point
{
    double x,y;
    int id;
    Point(double x=0,double y=0,int id=0):x(x),y(y),id(id) {}
} p[maxn],ch[maxn];
Point operator - (Point A,Point B)
{
    return Point(A.x - B.x, A.y - B.y , 0);
}
bool operator < (const Point& a, const Point& b)
{
    return a.x<b.x;
}
double Cross(Point A,Point B)
{
    return A.x*B.y-A.y*B.x;
}
double jisuan(Point A,Point B)
{
    return atan( fabs( (A.y-B.y) / (A.x-B.x) ) ) * 180 / pai;
}
bool cmp(Point A,Point B)
{
    return A.x>B.x;
}
void go()
{
    sort(p,p+n);
    int m=0;
    for(int i=0; i<n; i++)
    {
        if(i&&p[i].x==p[i-1].x)
        {
            ans[p[i].id]=ans[p[i-1].id];
            continue;
        }
        while(m>1 && Cross(ch[m-1]-ch[m-2] ,p[i]-ch[m-2]) >= 0) m--;
        if(p[i].id!=-1)
        {
            double now=jisuan(p[i],ch[m-1]);
            ans[p[i].id]-=now;
        }
        ch[m++]=p[i];
    }
    m=0;
    for(int i=n-1; i>=0; i--)
    {
        if(i!=n-1&&p[i].x==p[i+1].x)
        {
            ans[p[i].id]=ans[p[i+1].id];
            continue;
        }
        while(m>1 && Cross(p[i]-ch[m-2],ch[m-1]-ch[m-2]) >= 0) m--;
        if(p[i].id!=-1)
        {
            double now=jisuan(p[i],ch[m-1]);
            ans[p[i].id]-=now;
        }
        ch[m++]=p[i];
    }
}
int main()
{
    int T_T,test=1;
    scanf("%d",&T_T);
    while(T_T--)
    {
        int q;
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%lf%lf",&p[i].x,&p[i].y);
            p[i].id=-1;
        }
        scanf("%d",&q);
        for(int j=0; j<q; j++)
        {
            scanf("%lf",&p[n+j].x);
            p[n+j].y=0;
            p[n+j].id=j;
            ans[j]=180;
        }
        n+=q;
        go();
        printf("Case #%d:\n",test++);
        for(int i=0; i<q; i++)
            printf("%.10f\n",ans[i]);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: