您的位置:首页 > 理论基础 > 计算机网络

HDU 5033 Building (2014年北京赛区网络赛B题)

2015-09-04 22:47 435 查看
1.题目描述:点击打开链接

2.解题思路:本题利用单调栈解决。第一次做这个题用的在线处理,找左边和右边的极大值点,最后总是WA,然后才恍然大悟自己的方法错了,因为可能中间是一些低的楼,后面突然出现一个非常高的楼。因此一下子意识到本题要用单调栈来解决。

如果用单调栈解决,需要进行离线处理,把询问也当做坐标考虑进去,然后从左往右扫描,使栈中的结点构成的曲线呈现一种下降的,而且是上凸的样子,这样,栈顶元素就是我们要找的点,然后计算它和目标点之间和y轴的夹角。扫描完后,把整个数组翻转,但x值还要呈现从小到大的趋势(即只是把h值翻转了),然后再从左往右扫描一遍,最后累加和y轴的夹角,这样只需要O(N+Q)时间即可算出所有的答案。

3.代码:

#include<iostream>
#include<algorithm>
#include<cassert>
#include<string>
#include<sstream>
#include<set>
#include<bitset>
#include<vector>
#include<stack>
#include<map>
#include<queue>
#include<deque>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<ctime>
#include<cctype>
#include<complex>
#include<functional>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

#define me(s)  memset(s,0,sizeof(s))
#define rep(i,n) for(int i=0;i<(n);i++)
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair <int, int> P;

const int N=200100;
const int INF=100000000;
const double PI=acos(-1.0);
struct Node
{
    int x,h;
    bool operator<(const Node&a)const
    {
        return x<a.x;
    }
};

Node p
,st
;

double ans
;
int n,q;

int check(Node a,Node b,Node c)
{
    if(c.h<=0)c.h=0;
    return (ll)(a.h-c.h)*(c.x-b.x)>=(ll)(b.h-c.h)*(c.x-a.x);
}

double Angle(Node a,Node b)
{
    return atan(1.0*(b.x-a.x)/a.h);
}

void solve()
{
    int top=0;
    for(int i=0;i<n+q;i++)
    {
        if(p[i].h<=0)//如果是询问的点
        {
            while(top>=2&&check(st[top-2],st[top-1],p[i]))top--; //如果曲线呈现向下凸的趋势,出栈
            ans[-p[i].h]+=Angle(st[top-1],p[i]);//-p[i].h就是询问的下标
        }
        else
        {
            while(top&&st[top-1].h<=p[i].h)top--; //如果y值呈现递增趋势,出栈
            while(top>=2&&check(st[top-2],st[top-1],p[i]))top--; //如果曲线呈现向下凸的趋势,出栈
            st[top++]=p[i]; //入栈
        }
    }
}

int main()
{
    int T;
    scanf("%d",&T);
    for(int kase=1;kase<=T;kase++)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d",&p[i].x,&p[i].h);
        scanf("%d",&q);
        for(int i=0;i<q;i++)
        {
            scanf("%d",&p[i+n].x);
            p[i+n].h=-i; //用-i来标记询问的结点
        }
        me(ans);
        sort(p,p+n+q);
        solve();
        reverse(p,p+n+q); //翻转
        for(int i=0;i<n+q;i++)
            p[i].x=INF-p[i].x; //x仍然变为递增趋势
        solve();
        printf("Case #%d:\n",kase);
        for(int i=0;i<q;i++)
            printf("%.10lf\n",ans[i]/PI*180);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: