hdu5033Building 单调栈

来源:互联网 发布:土建计价软件 编辑:程序博客网 时间:2024/06/08 14:00

http://acm.split.hdu.edu.cn/showproblem.php?pid=5033

好题啊,不得不说是好题,尤其是听cys讲过后,简直茅塞顿开

题意:坐标轴上n个点上有高h的线段,q次查询,每次查询给一个坐标x,问在(x,0)点上看不到线段的视角范围是多少

离线求,讲查询点和线段点整合在一起排个序,求左边看不到线段的角,也就是和左边线段上端点的最大夹角,同方法求右边

求的方法:n^暴力明显不可行,会发现有很多点是不需要的,使用单调栈维护一个上凸包,因为只有上凸包上的点是之后随着x坐标的变大会影响结果的

对于线段点,判断和栈顶两个元素组成的是否为上凸包,不是则把最栈顶出栈,直到找到

对于查询点,如果和栈顶端点的夹角小于栈内第二个元素的夹角,则栈顶出栈,因为排过序之后的x坐标只会越来越大,因此当前夹角小,之后只会更小

反向再求一遍即可

#include<bits/stdc++.h>#define eps 1e-9#define PI 3.141592653589793#define bs 1000000007#define bsize 256#define MEM(a) memset(a,0,sizeof(a))typedef long long ll;using namespace std;struct node{    double x,h;    int id,flog;    bool operator < (const node u)const    {        if(x==u.x)        return flog>u.flog;        return x<u.x;    }}num[200005],sta[200005];int n,flag;double ans[200005];const double pai=180/acos(-1);double xielv(node u,node v){    return flag*(u.h-v.h)/(u.x-v.x);}void solve(){    int i,j,tail=0;    for(i=0;i<n;i++)    {        while(tail>1&&xielv(sta[tail-2],num[i])>xielv(sta[tail-1],num[i]))        tail--;        if(num[i].flog)        {            while(tail>0&&sta[tail-1].h<=num[i].h)            tail--;            sta[tail++]=num[i];        }        else        {            node temp=sta[tail-1];        //    cout<<temp.h<<" "<<temp.x<<" "<<num[i].h<<" "<<num[i].x<<endl;        //    cout<<atan(flag*(temp.h-num[i].h)/(temp.x-num[i].x))<<endl;            ans[num[i].id]+=pai*atan(flag*(temp.h-num[i].h)/(temp.x-num[i].x));        }    }    return ;}int main(){    int q,T,i,tca=1;    cin>>T;    while(T--)    {        cin>>n;        for(i=0;i<n;i++)        {            scanf("%lf %lf",&num[i].x,&num[i].h);            num[i].flog=1;        }        cin>>q;        for(i=n;i<n+q;i++)        {            scanf("%lf",&num[i].x);            num[i].h=0;            num[i].flog=0;            num[i].id=i-n;            ans[i-n]=0;        }        n+=q;        sort(num,num+n);        flag=-1;        solve();        reverse(num,num+n);        flag=1;        solve();        printf("Case #%d:\n",tca++);        for(i=0;i<q;i++)        printf("%.12lf\n",180-ans[i]);    }     }


原创粉丝点击