HDU 5033 单调栈

点击打开链接

题意:给了好多楼房的高度和位置,然后问一个人在一个位置,它可以看到的左右天空的角度

思路:用单调栈维护一个它能看到的最高的位置,然后反过来再求一遍,两遍的和就是结果了

#include <math.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define PI acos(-1.0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=400010;
inline int getint(){
    int res=0;
    char c=getchar();
    bool mi=false;
    while(c<'0' || c>'9') mi=(c=='-'),c=getchar();
    while('0'<=c && c<='9') res=res*10+c-'0',c=getchar();
    return mi ? -res : res;
}
struct edge{
    int x,y,id;
}num[maxn],stack1[maxn];
bool cmp(const edge &a,const edge &b){return a.x<b.x;}
double ans[maxn];
int calc(edge a,edge b,edge c){
    ll aa=(ll)(abs)(a.y-c.y)*abs(c.x-b.x);
    ll bb=(ll)(abs)(b.y-c.y)*abs(c.x-a.x);
    return aa>=bb;
}
double angle(edge a,edge b){
    return atan((double)(abs)(b.x-a.x)/(double)(a.y));
}
int main(){
    int T,n,cas=1,q;
    scanf("%d",&T);
    while(T--){
        n=getint();
        for(int i=0;i<n;i++) num[i].x=getint(),num[i].y=getint(),num[i].id=0;
        q=getint();
        for(int i=0;i<q;i++) num[n+i].x=getint(),num[n+i].y=0,num[n+i].id=i+1;
        sort(num,num+n+q,cmp);
        memset(ans,0,sizeof(ans));
        int len=0;
        for(int i=0;i<n+q;i++){
            if(num[i].id!=0){
                while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
                ans[num[i].id]+=angle(stack1[len-1],num[i]);
            }else{
                while(len&&stack1[len-1].y<=num[i].y) len--;
                while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
                stack1[len++]=num[i];
            }
        }
        len=0;
        for(int i=n+q-1;i>=0;i--){
            if(num[i].id!=0){
                while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
                ans[num[i].id]+=angle(stack1[len-1],num[i]);
            }else{
                while(len&&stack1[len-1].y<=num[i].y) len--;
                while(len>=2&&calc(stack1[len-2],stack1[len-1],num[i])) len--;
                stack1[len++]=num[i];
            }
        }
        printf("Case #%d:\n",cas++);
        for(int i=1;i<=q;i++) printf("%.10lf\n",ans[i]*180/PI);
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值