zoukankan      html  css  js  c++  java
  • hdu5033(单调栈)

    Building

    题意:

      x轴上有n栋高为hi的建筑,现在人在x轴上任意一个位置(保证左右一定有建筑,人的位置没有建筑,人的高可以视为0),求人所能看见的最大的天空的角度。如图所示:

      

    分析:

      整体思路就是维护一个相邻建筑顶连线斜率绝对值上升的单调栈,把建筑和人放在一起计算。首先我们考虑,什么情况下,建筑物会被其他的建筑物遮盖。

        1.a建筑比b建筑矮(a在b的左边),当人从b的右边看的时候,肯定是看不到a的,同理,a比b高,人从a左边也看不到b。

        2.如果a,b,c(从左到右)的高度如果成一个凹字型,那么b也是看不到的。

      然后我们就根据这两点来维护单调栈。当遇见人的时候,如果单调栈中建筑与人之间满足上面两点,则单调栈弹出元素,直到找到人左边(右边)所能够看到的最高的建筑,计算出视线与建筑的夹角即可。遇到建筑的时候,则只需要维护单调栈就好了。

      学习资料:大佬博客

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define Pi acos(-1.0)
    #define ll long long
    #define ull unsigned long long
    #define cls(x) memset(x,0,sizeof(x))
    #define clslow(x) memset(x,-1,sizeof(x))
    
    const int maxn=1e5+100;
    
    int n,q,top,tot,T;
    
    double ans[maxn];
    
    struct Node {
        int id;
        double x,h;
        Node()  {}
        Node(int id,double x,double h):id(id),x(x),h(h) {}
        bool operator < (const Node& rhs) const {
            return x<rhs.x;
        }
        Node operator - (const Node& rhs) const {
            return Node(0,abs(x-rhs.x),abs(h-rhs.h));
        }
    };
    //
    Node st[maxn<<1];
    Node node[maxn<<1];
    
    bool cross(Node a,Node b)
    {
        return b.h*a.x<a.h*b.x;
    }
    
    //如果为凹型,则中间的建筑物是看不到的
    bool judge(Node a,Node b,Node c)
    {
        return cross(c-a,c-b);
    }
    
    //注意算的是哪个角
    double angel(Node a,Node b)
    {
        return atan((b.x-a.x)/a.h);
    }
    
    void solve()
    {
        top=0;
        for(int i=1;i<=tot;i++){
            //如果是建筑物
            if(node[i].id==0){
                //去掉比当前矮的
                while(top&&st[top].h<=node[i].h)    top--;
                //去掉凹处
                while(top>=2&&judge(st[top-1],st[top],node[i]))    top--;
                st[++top]=node[i];
            }
            //如果是人
            else{
                while(top>=2&&judge(st[top-1],st[top],node[i]))    top--;
                ans[node[i].id]+=angel(st[top],node[i]);
            }
        }
    }
    
    int main()
    {
    //    freopen("in.txt","r",stdin);
        scanf("%d",&T);
        for(int kase=1;kase<=T;kase++){
            scanf("%d",&n);
            for(int i=1;i<=n;i++){
                node[i].id=0;
                scanf("%lf%lf",&node[i].x,&node[i].h);
            }
            tot=n;
            scanf("%d",&q);
            for(int i=1;i<=q;i++){
                tot++;
                node[tot].h=0;
                node[tot].id=i;
                scanf("%lf",&node[tot].x);
            }
    
            cls(ans);
            //计算左边的角度
            sort(node+1,node+tot+1);
            solve();
            //翻转,计算右边的角度
            reverse(node+1,node+tot+1);
            //最大的x变最小的x
            for(int i=1;i<=tot;i++) node[i].x=1e7-node[i].x;
            solve();
    
            printf("Case #%d:
    ",kase);
            for(int i=1;i<=q;i++){
                printf("%.10lf
    ",ans[i]*180/Pi);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    组合模式
    MySQL8.0 下载安装启动(Windows10)
    OI如逆旅,我亦是行人——省选
    闲话—江湖痴情浅,信步余生。平剑红烛,青丝微绾,却话奁中。
    此时彼方
    CSP 2019游记 & 退役记
    西狂 杨过
    SDOI 2019 Round1 游记
    NOIP2018游记
    未来可期,不知所终
  • 原文地址:https://www.cnblogs.com/shutdown113/p/9381140.html
Copyright © 2011-2022 走看看