hdu 5033 buiding(单调栈)

某年某月某天,马特去了一个小镇。这个小镇如此狭窄,以至于他可以把小镇当作一个枢纽。在镇上有一些摩天大楼,其中一栋位于xi,高度为hi。所有的摩天大楼位于不同的地方。为了简化题目,假设摩天大楼没有宽度。由于摩天大楼如此之高,马特几乎看不到天空。对于马特所在的位置,他想知道他能看到天空的角度范围有多大。假设马特的身高是0。可以保证,对于每个查询,马特的左右两边至少有一座建筑物,而且他的位置上没有建筑物。建筑物的数量n<1e5,查询次数Q<1e5。

我用常规思路,想不出什么好方法。既然这道题的普遍解法是单调栈,那么我们就来看一下单调栈怎么实现。首先,单调队列和单调栈的前提是,加入的元素满足一种有序的关系。所以我们自然而然地就想到,将所有查询排序,从左向右和从右向左分别进行查询的计算。以从左向右为例,如何做到在(均摊)O1的时间内找到一个查询的答案呢?我们先来找些性质。

性质1:如果一个建筑物i比它左侧的j高,那么当i和j都在马特左侧时,马特一定看不到j。也就是说,如果维护一个关于建筑物下标的单调栈,新加进来一个建筑时,可以把它左侧所有更矮的建筑删掉。那么,现在的单调栈就是单调递减的。这就去除了第一种冗余状态。

性质2:从左向右而言,如果有这样的情况:

,也就是单调栈中的顶上两个建筑和新加进来的建筑组成一个凹包(不好意思,下凸包),那么可以直接把单调栈顶的建筑删了,一直循环删下去。因为无论马特怎么站,都不会被它挡住。第二种冗余状态也被我们去除了。那么现在,单调栈存储的建筑就组成了一个上凸包。

性质3:然而,优化力度还不够大。这样子算法依然不是O(n)的。那怎么办呢?

由于马特一直往右跑,那么他与凸包相切的点只会往左移动:

所以,在加入新的建筑之后,判断一下马特与当前凸包的交点,然后将交点右侧的建筑全删了(弹出)即可。栈顶的建筑就是最优建筑(切线嘛)。这就去除了第三种冗余状态。然而这样的时间复杂度是均摊O(1)的吗?额,显然的。

这可能是目前为止我写的最详细的一篇博文。。

  1. #include <cmath>
  2. #include <cstdio>
  3. #include <algorithm>
  4. using namespace std;
  5. const int maxn=1e5+5;
  6. const double pi=3.1415926535898;
  7. struct stack{
  8. int t, a[maxn];
  9. void push(int x){ a[++t]=x; }
  10. void pop(){ if (--t==-1) ++t; }
  11. void reset(){ t=0; }
  12. inline int top(){ return a[t]; }
  13. inline int top2(){ return a[t-1]; }
  14. }s;
  15. struct query{
  16. int id, ans1, ans2; double x;
  17. }q[maxn], q2[maxn];
  18. struct building{
  19. double x, h;
  20. }b[maxn];
  21. int n, T, Q;
  22. bool cmp1(query &a, query &b){
  23. return a.x<b.x; }
  24. bool cmp2(query &a, query &b){
  25. return a.id<b.id; }
  26. bool cmpb(building &a, building &b){
  27. return a.x<b.x; }
  28. double angle(double x, double y){
  29. return atan(x/y)*180/pi;
  30. }
  31. int main(){
  32. scanf("%d", &T); int tmp=0;
  33. while (T--){
  34. ++tmp; s.reset();
  35. scanf("%d", &n);
  36. for (int i=1; i<=n; ++i)
  37. scanf("%lf%lf", &b[i].x, &b[i].h);
  38. scanf("%d", &Q);
  39. for (int i=1; i<=Q; ++i){
  40. scanf("%lf", &q[i].x);
  41. q[i].id=i;
  42. }
  43. sort(b+1, b+n+1, cmpb);
  44. sort(q+1, q+Q+1, cmp1);
  45. int nowbui=1; s.push(1);
  46. for (int i=1; i<=Q; ++i){
  47. while (b[nowbui+1].x<q[i].x){ //从左到右加入建筑物
  48. ++nowbui;
  49. //第一种冗余状态:左边的楼比右边的矮
  50. while (s.t>0&&b[s.top()].h<=b[nowbui].h) s.pop();
  51. //所以现在这个建筑物序列严格下降
  52. //第二种冗余状态:是个下凸函数
  53. while (s.t>1&&(b[nowbui].h-b[s.top()].h)/
  54. (b[nowbui].x-b[s.top()].x)>=
  55. (b[s.top()].h-b[s.top2()].h)/
  56. (b[s.top()].x-b[s.top2()].x)) s.pop();
  57. //所以现在这个建筑物序列是凸包了
  58. s.push(nowbui);
  59. }
  60. //第三种冗余状态:若一栋楼在视线所切的那栋楼的右边,则可以删去
  61. //可以用均摊,证明这里的复杂度是常数
  62. while (s.t>1&&(b[s.top2()].h)/(q[i].x-b[s.top2()].x)>
  63. (b[s.top()].h)/(q[i].x-b[s.top()].x)) s.pop();
  64. //现在终于不仅排除了冗余状态,并且找到了最优解。
  65. q[i].ans1=s.top();
  66. } //从右往左也一样
  67. nowbui=n; s.reset(); s.push(n);
  68. for (int i=Q; i>=1; --i){
  69. while (b[nowbui-1].x>q[i].x){
  70. --nowbui;
  71. //右边的楼比左边的矮
  72. while (s.t>0&&b[s.top()].h<=b[nowbui].h) s.pop();
  73. //下面有图 (其实这里封装一个关于斜率的函数会更好)
  74. while (s.t>1&&(b[nowbui].h-b[s.top()].h)/
  75. (b[nowbui].x-b[s.top()].x)<=
  76. (b[s.top()].h-b[s.top2()].h)/
  77. (b[s.top()].x-b[s.top2()].x)) s.pop();
  78. s.push(nowbui);
  79. }
  80. //下面有图
  81. while (s.t>1&&b[s.top2()].h/(b[s.top2()].x-q[i].x)>
  82. b[s.top()].h/(b[s.top()].x-q[i].x)) s.pop();
  83. q[i].ans2=s.top();
  84. }
  85. sort(q+1, q+Q+1, cmp2);
  86. printf("Case #%d:\n", tmp);
  87. for (int i=1; i<=Q; ++i){
  88. printf("%.5lf\n", 180-angle(b[q[i].ans1].h,
  89. q[i].x-b[q[i].ans1].x)-angle(b[q[i].ans2].h,
  90. b[q[i].ans2].x-q[i].x));
  91. }
  92. }
  93. // printf("%.6lf", angle(1, 1));
  94. return 0;
  95. }

hdu 5033 buiding(单调栈)的更多相关文章

  1. HDU 5033 Building(单调栈)

    HDU 5033 Building(单调栈) 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5033 Description Once upon a ti ...

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

    Description Once upon a time Matt went to a small town. The town was so small and narrow that he can ...

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

    题意:有一排建筑,每座建筑有一定的高度,宽度可以忽略,求在某点的平地上能看到天空的最大角度. 网上的做法基本都是离线的...其实这道题是可以在线做的. 对于向右能看到的最大角度,从右往左倍增维护每个时 ...

  4. HDU 5033 Building(单调栈维护凸包)

    盗张图:来自http://blog.csdn.net/xuechelingxiao/article/details/39494433 题目大意:有一排建筑物坐落在一条直线上,每个建筑物都有一定的高度, ...

  5. hdu 5033 模拟+单调优化

    http://acm.hdu.edu.cn/showproblem.php?pid=5033 平面上有n个建筑,每个建筑由(xi,hi)表示,m组询问在某一个点能看到天空的视角范围大小. 维护一个凸包 ...

  6. Largest Rectangle in a Histogram HDU - 1506 (单调栈)

    A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rec ...

  7. HDU 1506【单调栈】

    思路: 转化成对于某一位置为最小值求向两边最远>=他的位置,用单调栈就能轻易完成. 那么ans=(left+right)*h[i]; 维护单调递增还是递减呢? 我们能很快反应到,一旦碰到一个比他 ...

  8. HDU 3410【单调栈】

    思路: 单调栈. 鄙人的记忆:按当前为最大值的两边延伸就是维护单调递减栈. //#include <bits/stdc++.h> #include <iostream> #in ...

  9. Hdu 4923(单调栈)

    题目链接 Room and Moor Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

随机推荐

  1. Java反射详解(转)

    原文地址:http://www.importnew.com/17616.html 动态语言 动态语言,是指程序在运行时可以改变其结构:新的函数可以被引进,已有的函数可以被删除等在结构上的变化.比如众所 ...

  2. RaspBerry Pi3 ~ 内核编译

    RaspBerryPi3-内核编译 转载注明出处:http://www.cnblogs.com/einstein-2014731/p/5985128.html 在有道云笔记的同步分享:http://n ...

  3. 《CSS权威指南(第三版)》---第五章 字体

    这章主要的内容有: 1.字体:一般使用一种通用的字体. 2.字体加粗:一般从数字100 -900 . 3.字体大小:font-size 4.拉伸和调整字体:font-stretch 5.调整字体大小: ...

  4. Hadoop- HDFS的Safemode

    Hadoop- HDFS的Safemode hadoop启动时,NameNode启动完后就开始进入安全模式,等待DataNode向NameNode发送block report ,当datanode b ...

  5. frp支持httpIP地址加端口号访问

    (一)安装就不再多说 传送门:https://blog.csdn.net/superljn/article/details/81289993 (二)vim frps.ini [common] bind ...

  6. Linux_服务器_06_VMware虚拟机下安装CentOS7.0图文教程

    二.参考资料 1.VMware虚拟机下安装CentOS7.0图文教程

  7. fiddler篡改请求数据

    有时需要修改请求或返回结果来验证网站存在的漏洞,因此需要使用到fiddler的断点功能. 如何修改请求前数据? 1.设置请求前断点 Rules--Automatic breakpoints--befo ...

  8. ACM学习历程——HDU5202 Rikka with string(dfs,回文字符串)

    Problem Description As we know, Rikka is poor at math. Yuta is worrying about this situation, so he ...

  9. javacpp-FFmpeg系列补充:FFmpeg拉流截图实现在线演示demo(视频截图并返回base64图像,支持jpg/png/gif/bmp等多种格式)

    javacpp-ffmpeg系列: javacpp-FFmpeg系列之1:视频拉流解码成YUVJ420P,并保存为jpg图片 javacpp-FFmpeg系列之2:通用拉流解码器,支持视频拉流解码并转 ...

  10. Mesos的quorum配置引发的问题

    Mesos安装完毕后,发现agent无法和master关联(通过WebUI的agent页面无法看到agent信息),查看日志显示: Elected as the leading master! sta ...