hdu 5033 单调栈+凸包

将人看成高度为0的楼,与楼混在一起按照横坐标排序,用单调栈正着扫一遍,再反着扫一遍,分别求出竖直线两侧的高度

出栈的条件:

1.当前楼的高度比栈顶的楼高

2.为了维护凸包的性质,若栈顶和之前楼的斜率大于栈顶和当前楼的斜率(均为绝对值),出栈

3.如果当前楼是人,向前出栈直至找到栈顶楼与人夹角大于之前的楼与人的夹角

然后将竖直线两侧的夹角相加就是最后结果

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <stack>
#include <cmath>
#define MAX 100007
#define PI (acos(-1))

using namespace std;

typedef pair<int,int> PII;

stack<PII> stk;

struct Building 
{
    int h,x,id;
    bool operator < ( const Building& b ) const
    {
        return x < b.x;
    }
}b[MAX<<1];

int t,n,m;
double ans[MAX];

double slope ( int id1 , int id2 )
{
    return fabs ( ( b[id1].h - b[id2].h ) * 1.0 / ( ( b[id1].x - b[id2].x ) *1.0) ) ;
}

bool check ( int i )
{
    if ( stk.empty() ) return false;
    if ( stk.top().first == -1 ) return false;
    if ( slope ( stk.top().first , stk.top().second ) > slope ( stk.top().second , i ) )
        return true;
    return false;
}

void solve ( int s , int e , int d )
{
    while ( !stk.empty() ) stk.pop ( );
    stk.push ( make_pair ( -1 , s ) );
    for ( int i = s+d ; i != e ; i+= d )
    {
        if ( b[i].h )
        {
            while ( !stk.empty() && b[stk.top().second].h <= b[i].h )
                stk.pop ( );
            while ( check ( i ) )
                stk.pop ( );
            if ( stk.empty() ) stk.push ( make_pair ( -1 , i ) );
            else stk.push ( make_pair ( stk.top().second , i ) );
        }
        else 
        {
            while ( stk.top().first != -1 &&slope ( stk.top().second , i ) < slope ( stk.top().first , i ) )
                stk.pop ( );
            ans[b[i].id] += atan ( 1.0/slope ( stk.top().second , i ) )/PI*180.0;
        }
    }
}

int main ( )
{
    scanf ( "%d" , &t );
    int c = 1;
    while ( t-- )
    {
        scanf ( "%d" , &n );
        for ( int i = 1 ; i <= n ; i++ )
        {
            scanf ( "%d%d" , &b[i].x , &b[i].h );
            b[i].id = -1;
        }
        scanf ( "%d" , &m );
        for ( int i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d" , &b[i+n].x );
            b[i+n].h = 0;
            b[i+n].id = i;
        }
        sort ( b+1 , b+n+m+1 );
        memset ( ans , 0 , sizeof ( ans ) );
        solve ( 1 , n+m , 1 );
        solve ( n+m , 1 , -1 );
        printf ( "Case #%d:\n" , c++ );
        for ( int i = 1 ; i <= m ; i++ )
            printf( "%.10lf\n" , ans[i] );
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值