hdu5033 Building (单调栈+)

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

2014 ACM/ICPC Asia Regional Beijing Online B 1002

Building

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 0    Accepted Submission(s): 0
Special Judge

Problem Description

Once upon a time Matt went to a small town. The town was so small and narrow that he can regard the town as a pivot. There were some skyscrapers in the town, each located at position xi with its height hi. All skyscrapers located in different place. The skyscrapers had no width, to make it simple. As the skyscrapers were so high, Matt could hardly see the sky.Given the position Matt was at, he wanted to know how large the angle range was where he could see the sky. Assume that Matt‘s height is 0. It‘s guaranteed that for each query, there is at least one building on both Matt‘s left and right, and no building locate at his position.

Input

The first line of the input contains an integer T, denoting the number of testcases. Then T test cases follow.

Each test case begins with a number N(1<=N<=10^5), the number of buildings.

In the following N lines, each line contains two numbers, xi(1<=xi<=10^7) and hi(1<=hi<=10^7).

After that, there‘s a number Q(1<=Q<=10^5) for the number of queries.

In the following Q lines, each line contains one number qi, which is the position Matt was at.

Output

For each test case, first output one line "Case #x:", where x is the case number (starting from 1).

Then for each query, you should output the angle range Matt could see the sky in degrees. The relative error of the answer should be no more than 10^(-4).

Sample Input

3
3
1 2
2 1
5 1
1
4
3
1 3
2 2
5 1
1
4
3
1 4
2 3
5 1
1
4

Sample Output

Case #1:
101.3099324740
Case #2:
90.0000000000
Case #3:
78.6900675260

题意:

城市看做二维平面,建筑看做x轴上某个位置为端点的竖着的线段,(xi,hi)表示在x轴xi位置有个高为hi的建筑(线段)。有多次询问,每次问人在某个平地上(x,0)能看到天空的角度。

题解:

维护 相邻两建筑顶(xi,hi)的连线的斜率的绝对值上升 的单调栈。

先把建筑和queries的点全部弄到一起,按xi排个序。然后从左到右来一波得出在某个空地往左看看到最高的是哪个建筑,再反过来来一波。

先按从左到右的情况来说:

维护单调栈,栈里存的是之后的空地可能看到的建筑,容易知这是递减的单调栈。

再思考,如果:

则只用存两边的点,中间那3个肯定看不到了。

如果:

则都要存,因为往右走的时候走着走着,右边第二个就比右边第一个高了,走着走着右边第三个又比右边第二个高了……(这时pop掉栈顶

可见我们存的是相邻两建筑顶(xi,hi)的连线的斜率的绝对值上升 的单调栈

每看到一个空地,把栈首的不够高的都pop到,只留下那个能看到的最高的,然后把这个建筑加入结果记录中。(记录从这个空地往左看看到的最高的是哪个建筑)

反过来再来一遍。

最后再对询问搞一搞,就完啦。

(我写的时候以为xi hi是整数,所以里面都是用整数搞的,后来看Clarify才发现是实数,改了一波)

代码:

  1 //#pragma comment(linker, "/STACK:102400000,102400000")
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<iostream>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<map>
  9 #include<set>
 10 #include<stack>
 11 #include<queue>
 12 using namespace std;
 13 #define ll long long
 14 #define usll unsigned ll
 15 #define mz(array) memset(array, 0, sizeof(array))
 16 #define mf1(array) memset(array, -1, sizeof(array))
 17 #define minf(array) memset(array, 0x3f, sizeof(array))
 18 #define REP(i,n) for(i=0;i<(n);i++)
 19 #define FOR(i,x,n) for(i=(x);i<=(n);i++)
 20 #define RD(x) scanf("%d",&x)
 21 #define RD2(x,y) scanf("%d%d",&x,&y)
 22 #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z)
 23 #define WN(x) printf("%d\n",x);
 24 #define RE  freopen("D.in","r",stdin)
 25 #define WE  freopen("huzhi.txt","w",stdout)
 26 #define mp make_pair
 27 #define pb push_back
 28 const double pi=acos(-1.0);
 29 const double eps=1e-10;
 30
 31 const int maxn=111111;
 32 const int maxm=2*maxn;
 33
 34 struct Bd {
 35     double x,h;
 36     int q;
 37 } a[maxm];
 38 int n,Q;
 39 double q[maxn];
 40
 41 bool cmp(Bd x,Bd y) {
 42     return x.x<y.x;
 43
 44 }
 45
 46 int L[maxn],R[maxn];///对应q[]
 47
 48 int b[maxn];///a[b[]].h 降序单调队列,并且相邻斜率(Δh/Δx)依次更斜
 49 int r;
 50
 51 void mypb(int x) {
 52     while(r>0 && a[b[r-1]].h <= a[x].h)r--;///保持降序
 53     ///要保持:a[x]与a[b[r-1]]的斜率(负数) 小于 a[b[r-1]]与a[b[r-2]]的
 54     ///(a[x].h - a[b[r-1]].h)/(a[x].x - a[b[r-1]].x) < (a[b[r-1]].h - a[b[r-2]].h)/(a[b[r-1]].x - a[b[r-2]].x)
 55     ///(a[x].h - a[b[r-1]].h)*(a[b[r-1]].x - a[b[r-2]].x)<(a[b[r-1]].h - a[b[r-2]].h)*(a[x].x - a[b[r-1]].x)
 56     ///实数
 57     while(r>1 && ((a[x].h - a[b[r-1]].h))*(fabs(a[b[r-1]].x - a[b[r-2]].x))>=((a[b[r-1]].h - a[b[r-2]].h))*(fabs(a[x].x - a[b[r-1]].x)))
 58         r--;///保持斜率
 59     b[r++]=x;
 60     //printf("PUSH b[%d]=%d\t%d %d\tr=%d\n",r-1,x,a[x].x,a[x].h,r);
 61 }
 62
 63 void farm() {
 64     int i;
 65     ///一共有n+Q个元素,在1~n+Q里
 66     int m=n+Q;
 67     sort(a+1,a+m+1,cmp);
 68     a[0].x=0;
 69     a[0].h=0;
 70     r=1;
 71     b[0]=0;
 72     FOR(i,1,m) {
 73         //printf("a[%d].x=%d , .h=%d\n",i,a[i].x,a[i].h);
 74         if(a[i].h>0.0)mypb(i);
 75         else {
 76             ///从队尾,找到对于x最斜的那个
 77             ///当 a[b[r-1]].h/(a[i].x - a[b[r-1]].x) <= a[b[r-2]].h/(a[i].x - a[b[r-2]].x)时pop
 78             ///  a[b[r-1]].h*(a[i].x - a[b[r-2]].x) <= a[b[r-2]].h*(a[i].x - a[b[r-1]].x)
 79             ///实数
 80             while(r>1 && (a[b[r-1]].h)*(fabs(a[i].x - a[b[r-2]].x)) <= (a[b[r-2]].h)*(fabs(a[i].x - a[b[r-1]].x))) {
 81                 //printf("POP %d %d\n",a[b[r-1]].x,a[b[r-1]].h);
 82                 r--;
 83             }
 84             //printf("!r=%d!\n",r);
 85             L[a[i].q]=b[r-1];
 86             //printf("L[%d]=b[%d]=%d\tr=%d\n",-a[i].h,r-1,b[r-1],r);
 87         }
 88     }
 89
 90     ///右边开始
 91     a[m+1].x=a[m].x+1;
 92     a[m+1].h=0;
 93     r=1;
 94     b[0]=m+1;
 95     for(i=m; i>=1; i--) {
 96         //printf("a[%d].x=%d , .h=%d\n",i,a[i].x,a[i].h);
 97         if(a[i].h>0)mypb(i);
 98         else {
 99             ///从队尾,找到对于x最斜的那个
100             ///当 a[b[r-1]].h/(a[i].x - a[b[r-1]].x) <= a[b[r-2]].h/(a[i].x - a[b[r-2]].x)时pop
101             ///  a[b[r-1]].h*(a[i].x - a[b[r-2]].x) <= a[b[r-2]].h*(a[i].x - a[b[r-1]].x)
102             ///可能超int
103             while(r>1 && (a[b[r-1]].h)*(fabs(a[i].x - a[b[r-2]].x)) <= (a[b[r-2]].h)*(fabs(a[i].x - a[b[r-1]].x))) {
104                 //printf("POP %d %d\n",a[b[r-1]].x,a[b[r-1]].h);
105                 r--;
106             }
107             R[a[i].q]=b[r-1];
108             //printf("L[%d]=%d\n",-a[i].h,b[r-1]);
109         }
110     }
111 }
112
113 double gank(int x) {
114     Bd lb=a[L[x]];
115     Bd rb=a[R[x]];
116     //printf("%d %d %d %d\n",lb.x,lb.h,rb.x,rb.h);
117     double lj=atan2((lb.h),(fabs(lb.x-q[x])));
118     double rj=atan2((rb.h),(fabs(rb.x-q[x])));
119     return (pi-lj-rj)/pi*180.0;
120 }
121
122 int main() {
123     int T,cas=1;
124     int i;
125     RD(T);
126     while(T--) {
127         RD(n);
128         FOR(i,1,n)scanf("%lf%lf",&a[i].x,&a[i].h);
129         RD(Q);
130         FOR(i,1,Q) {
131             scanf("%lf",&q[i]);
132             a[n+i].x=q[i];
133             a[n+i].h=0.0;
134             a[n+i].q=i;///这是第i个请求
135         }
136         farm();
137         printf("Case #%d:\n",cas++);
138         FOR(i,1,Q) {
139             printf("%.10lf\n",gank(i));
140         }
141     }
142     return 0;
143 }

时间: 2024-10-09 16:09:02

hdu5033 Building (单调栈+)的相关文章

HDU5033 Building(单调栈)

题意是说在水平轴上有很多建筑物(没有宽度),知道每个建筑物的位置与高度.有m个查询,每次查询位置x所能看到的天空的角度. 方法是将建筑与查询一起排序,从左往右计算一遍,如果是建筑物,则比较最后两个(当前的与队尾的)斜率与队尾两个的斜率比较,如果较小则入队,否则一直出队尾元素直至满足条件(因为斜率为负数,斜率较小说明越堵). 如果是查询,同样的比较这个位置与队尾的斜率同队尾两个元素的斜率比较,直至满足小于的关系结束,这时计算垂直方向左侧的夹角 最后从右往左计算右边,求和便是答案 1 #pragma

hdu 5033 Building (单调栈 或 暴力枚举 )

Description Once upon a time Matt went to a small town. The town was so small and narrow that he can regard the town as a pivot. There were some skyscrapers in the town, each located at position x i with its height h i. All skyscrapers located in dif

HDU - 5033 Building (单调栈+倍增)

题意:有一排建筑,每座建筑有一定的高度,宽度可以忽略,求在某点的平地上能看到天空的最大角度. 网上的做法基本都是离线的...其实这道题是可以在线做的. 对于向右能看到的最大角度,从右往左倍增维护每个时刻的单调栈(凸壳),对于每个询问,先二分找到它右面的第一个建筑的位置,然后在对应的凸壳上倍增找到切点即可. 向左看把x坐标对称一下就行. 复杂度$O(nlogn)$ 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long lo

HDU 5033 Building(北京网络赛B题) 单调栈 找规律

做了三天,,,终于a了... 11724203 2014-09-25 09:37:44 Accepted 5033 781MS 7400K 4751 B G++ czy Building Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 1257    Accepted Submission(s): 358 Special Judg

HDU 5033 Building(2014北京网络赛 单调栈+几何)

博客原文地址:http://blog.csdn.net/xuechelingxiao/article/details/39494433 Building 题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度,给出一个X坐标,高度为0,问X位置能看到的视角是多少度.如图: 图一: 图二: 图一为样例一,图二为样例三,红色部分为高楼,蓝色虚线为视角的最大范围. 解题思路: 由于有10w个点跟10w次询问,所以朴素的算法判断肯定会超时的.所以就需要用单调栈,维护相邻两建筑顶(xi,hi)的

hdu - 5033 - Building(单调栈)

题意:N 幢楼排成一列(1<=N<=10^5),各楼有横坐标 xi(1<=xi<=10^7) 以及高度 hi(1<=hi<=10^7),在各楼之间的Q个位置(1<=Q<=10^5),问这些位置可以仰望天空的夹角是多少度. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5033 -->>将楼和人的位置一起按 x 排序.. 从左往右扫,单调栈维护斜率小的.. 从右往左扫,单调栈维护斜率大的.. #inc

HDU 5033 Building (维护单调栈)

题目链接 题意:n个建筑物,Q条询问,问所在的位置,看到天空的角度是多少,每条询问的位置左右必定是有建筑物的. 思路 : 维护一个单调栈,将所有的建筑物和所有的人都放到一起开始算就行,每加入一个人,就维护栈里的建筑物的高度,也就是说这个人所能够看到的建筑物时在栈里的,但是这个人看不到的就删掉,例如下图,中间三个点可以删掉了,因为角度问题中间三个是看不到的,所以不会影响最终求得角度 还有一种情况,就是下述的情况,不停的维护单调栈,人站在不同的地方角度也是不一样的. 维护的是相邻两建筑顶(xi,hi

HDU 5033---Building(单调栈)

题目链接 Problem Description Once upon a time Matt went to a small town. The town was so small and narrow that he can regard the town as a pivot. There were some skyscrapers in the town, each located at position xi with its height hi. All skyscrapers loc

HDU4252 ACM fighting(单调栈)

Description After Mr. B arrived in Warsaw, he was shocked by the skyscrapers and took several photos. But now when he looks at these photos, he finds in surprise that he isn't able to point out even the number of buildings in it. So he decides to wor