• HDU 5033 Building --离线+单调栈


    题意:给一些建筑物,x表示横坐标,h表示高度,然后查询某些坐标x,问从该点看向天空的最大张角是多大。

    解法:离线操作,读入所有数据,然后按x升序排序,对每一个查询的x,先从左到右,依次添加x坐标小于x的建筑物,加入一个建筑物的条件:

    1.此建筑物高度大于栈中的前一个,这个必然是最优的。

    2.加入这个建筑物后不能使相对斜率: stk[top-2]~stk[top-1] 比a[j]~stk[top-1]大(负数),即出现凹形,否则会出现这种:

    如图,即中间那个根本没用了,加入第三根的时候就要判一下。

    最后算这个查询x的左角度的时候,要先判断这个点跟栈中上面两个的关系,处理一下。

    然后再从右到左扫一遍,最后就得出了左右角。

    之前没考虑相对斜率,而是每次加建筑物的时候,只判断与此时的查询点的绝对斜率关系,这样的bug就是会形成上图中的情况。(好蒻)

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #define pi (acos(-1.0))
    #define eps 1e-7
    using namespace std;
    #define N 100007
    
    struct Query
    {
        double x;
        double Lang,Rang;
        int ind;
    }ans[N];
    
    struct node
    {
        double x,h;
    }a[N];
    int stk[N],top;
    int cmp1(Query ka,Query kb) { return ka.x < kb.x; }
    int cmp2(Query ka,Query kb) { return ka.ind < kb.ind; }
    int cmpB(node ka,node kb)   { return ka.x < kb.x; }
    
    int main()
    {
        int t,cs = 1,i,j;
        int n,m;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            for(i=1;i<=n;i++)
                scanf("%lf%lf",&a[i].x,&a[i].h);
            sort(a+1,a+n+1,cmpB);
            scanf("%d",&m);
            for(i=1;i<=m;i++)
            {
                scanf("%lf",&ans[i].x);
                ans[i].ind = i;
            }
            sort(ans+1,ans+m+1,cmp1);
            double now;
            top = 0;
            j = 1;
            for(i=1;i<=m;i++)
            {
                while(j <= n && a[j].x < ans[i].x)
                {
                    while(top >= 1 && a[j].h >= a[stk[top-1]].h)           //高度大于之前的,肯定更优
                        top--;
                    while(top >= 2 && (a[j].h-a[stk[top-1]].h)/(fabs(a[j].x-a[stk[top-1]].x)) >= (a[stk[top-1]].h-a[stk[top-2]].h)/(fabs(a[stk[top-1]].x-a[stk[top-2]].x)))
                        top--;                                             //相对斜率递减(负数)
                    stk[top++] = j;
                    j++;
                }
                while(top >= 2 && a[stk[top-1]].h/(fabs(a[stk[top-1]].x-ans[i].x)) <= a[stk[top-2]].h/(fabs(a[stk[top-2]].x-ans[i].x)))
                    top--;                                                 //对这个点
                now = a[stk[top-1]].h/(fabs(a[stk[top-1]].x-ans[i].x));    //最终答案为栈顶的建筑
                ans[i].Lang = 180.0*atan2(now,1.0)/pi;
            }
            top = 0;              //反着来一遍
            j = n;
            for(i=m;i>=1;i--)
            {
                while(j >= 1 && a[j].x > ans[i].x)
                {
                    while(top >= 1 && a[j].h >= a[stk[top-1]].h)
                        top--;
                    while(top >= 2 && (a[j].h-a[stk[top-1]].h)/(fabs(a[j].x-a[stk[top-1]].x)) >= (a[stk[top-1]].h-a[stk[top-2]].h)/(fabs(a[stk[top-1]].x-a[stk[top-2]].x)))
                        top--;
                    stk[top++] = j;
                    j--;
                }
                while(top >= 2 && a[stk[top-1]].h/(fabs(a[stk[top-1]].x-ans[i].x)) <= a[stk[top-2]].h/(fabs(a[stk[top-2]].x-ans[i].x)))
                    top--;
                now = a[stk[top-1]].h/(fabs(a[stk[top-1]].x-ans[i].x));
                ans[i].Rang = 180.0*atan2(now,1.0)/pi;
            }
            sort(ans+1,ans+m+1,cmp2);
            printf("Case #%d:
    ",cs++);
            for(i=1;i<=m;i++)
                printf("%.10f
    ",180.0-ans[i].Lang-ans[i].Rang);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【洛谷】1852:[国家集训队]跳跳棋【LCA】【倍增?】
    【POJ】1835:宇航员【模拟】【三维行走】
    【BZOJ】3195: [Jxoi2012]奇怪的道路【状压/奇偶性】【思路】
    【10.24校内测试】【欧拉路径(有向+无向)】【双向链表/树状数组/线段树】
    【POJ】1840:Eqs【哈希表】
    【洛谷】4317:花神的数论题【数位DP】
    【POJ】1486:Sorting Slides【二分图关键边判定】
    算法模板
    Redis源码阅读一:简单动态字符串SDS
    总结下c/c++的一些调试经验
  • 原文地址:https://www.cnblogs.com/whatbeg/p/3985088.html
Copyright © 2020-2023  润新知