Atlantis

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 11514    Accepted Submission(s): 4891

Problem Description
There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.
 
Input
The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

The input file is terminated by a line containing a single 0. Don’t process it.

 
Output
For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

Output a blank line after each test case.

 
Sample Input
2
10 10 20 20
15 15 25 25.5
0
 
Sample Output
Test case #1
Total explored area: 180.00
 
记得最开始学线段树的时候就看过这道题,我是完全懵逼的,本以为有生之年也不能弄懂这道题的思路,结果时至今日,总算是弄懂了传说中的扫描线。
 

struct segment       //这就是传说中的扫描线
{
  double l,r,h;     //l,r是左右端点,h为高度
  int f;     //上边f为-1,下边为1
}ss[2*MAXN];      //ss存的是所有矩形的上下边的信息

 
思路:
扫描线从下往上扫,所以离散化横坐标,因为我们每扫到一条边,就要update,即将这条边投影到总区间上,那么怎么update呢,线段上的点的坐标是double,所以我们离散化横坐标。用一个pos数组存储每个点的横坐标,下标为第几个点,我们将pos从小到大排序并去重,去重后的点个数为m,此时就可以建树了build(0,m-1,1);为什么这样建树,仔细一想应该能明白。
将ss(边)按高度升序排序,遍历,遍历到一条边,则在pos中搜索其左右端点在pos中的下标。如果是下边,将其投影到总区间,若是上边,则在总区间中将其对应下边的投影去掉。然后加上此次算出的一块面积。
 
 
注意:
扫描线段时r-1:int R=search(s[i].l,hash,m)-1; 
计算底边长时r+1:if(mark[n])sum[n]=hash[right+1]-hash[left]; 
解释:假设现在有一个线段左端点是l=0,右端点是r=m-1 
则我们去更新的时候,会算到sum[1]=hash[mid]-hash[left]+hash[right]-hash[mid+1] 
这样的到的底边长sum是错误的,why?因为少算了mid~mid+1的距离,由于我们这利用了 
离散化且区间表示线段,所以mid~mid+1之间是有长度的,比如hash[3]=1.2,hash[4]=5.6,mid=3 
所以这里用r-1,r+1就很好理解了   
  1. #include<cstdio>
  2. #include<set>
  3. #include<iostream>
  4. #include<vector>
  5. #include<algorithm>
  6. #include<map>
  7. #include<cmath>
  8. #include<string>
  9. #include<cstring>
  10. using namespace std;
  11. #define MAXN 105
  12. #define lson l,mid,rt<<1
  13. #define rson mid+1,r,rt<<1|1
  14.  
  15. struct segment
  16. {
  17. double l,r,h;
  18. int f;
  19. }ss[*MAXN];
  20.  
  21. struct Node
  22. {
  23. int l,r;
  24. int cnt;
  25. double len;
  26. int mid()
  27. {
  28. return (l+r>>);
  29. }
  30. }tt[*MAXN*];
  31.  
  32. double pos[*MAXN];
  33. int nums;
  34.  
  35. bool cmp(segment a,segment b)
  36. {
  37. return a.h<b.h;
  38. }
  39.  
  40. void build(int l,int r,int rt)
  41. {
  42. tt[rt].l=l;
  43. tt[rt].r=r;
  44. tt[rt].cnt=;
  45. tt[rt].len=;
  46. if(l==r)
  47. return;
  48. int mid=(l+r)>>;
  49. build(lson);
  50. build(rson);
  51. }
  52.  
  53. int binary(double key,int l,int r)
  54. {
  55. while(l<=r)
  56. {
  57. int mid=(l+r)>>;
  58. if(pos[mid]==key)
  59. return mid;
  60. else if(key<pos[mid])
  61. r=mid-;
  62. else
  63. l=mid+;
  64. }
  65. return -;
  66. }
  67.  
  68. void get_len(int rt)
  69. {
  70. if(tt[rt].cnt)
  71. tt[rt].len=pos[tt[rt].r+]-pos[tt[rt].l];
  72. else if(tt[rt].l==tt[rt].r)
  73. tt[rt].len=;
  74. else
  75. tt[rt].len=tt[rt<<].len+tt[rt<<|].len;
  76. }
  77.  
  78. void update(int l,int r,int val,int rt)
  79. {
  80. if(tt[rt].l==l&&tt[rt].r==r)
  81. {
  82. tt[rt].cnt+=val;
  83. get_len(rt);
  84. return;
  85. }
  86. int mid=tt[rt].mid();
  87. if(r<=mid)
  88. update(l,r,val,rt<<);
  89. else if(l>mid)
  90. update(l,r,val,rt<<|);
  91. else
  92. {
  93. update(l,mid,val,rt<<);
  94. update(mid+,r,val,rt<<|);
  95. }
  96. get_len(rt);
  97. }
  98.  
  99. int main()
  100. {
  101. int cas=;
  102. int n;
  103. while(scanf("%d",&n)!=EOF&&n)
  104. {
  105. nums=;
  106. for(int i=;i<n;i++)
  107. {
  108. double x1,x2,y1,y2;
  109. scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
  110. ss[nums].l=x1;ss[nums].r=x2;ss[nums].h=y1;ss[nums].f=-;
  111. ss[nums+].l=x1;ss[nums+].r=x2;ss[nums+].h=y2;ss[nums+].f=;
  112. pos[nums]=x1;pos[nums+]=x2;
  113. nums+=;
  114. }
  115. sort(ss,ss+nums,cmp);
  116. sort(pos,pos+nums);
  117. int m=;
  118. for(int i=;i<nums;i++)
  119. if(pos[i]!=pos[i-])
  120. pos[m++]=pos[i];
  121. build(,m-,);
  122. double ans=;
  123. for(int i=;i<nums;i++)
  124. {
  125. int l=binary(ss[i].l,,m-);
  126. int r=binary(ss[i].r,,m-)-;
  127. update(l,r,ss[i].f,);
  128. ans+=(ss[i+].h-ss[i].h)*tt[].len;
  129. }
  130. printf("Test case #%d\n",++cas);
  131. printf("Total explored area: %.2f\n\n",ans);
  132. }
  133. return ;
  134. }
 

HDU_1542_线段树【扫描线】的更多相关文章

  1. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  2. Codeforces VK CUP 2015 D. Closest Equals(线段树+扫描线)

    题目链接:http://codeforces.com/contest/522/problem/D 题目大意:  给你一个长度为n的序列,然后有m次查询,每次查询输入一个区间[li,lj],对于每一个查 ...

  3. 【POJ-2482】Stars in your window 线段树 + 扫描线

    Stars in Your Window Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11706   Accepted:  ...

  4. HDU 4419 Colourful Rectangle --离散化+线段树扫描线

    题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何 ...

  5. BZOJ-3228 棋盘控制 线段树+扫描线+鬼畜毒瘤

    3228: [Sdoi2008]棋盘控制 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 23 Solved: 9 [Submit][Status][D ...

  6. BZOJ-3225 立方体覆盖 线段树+扫描线+乱搞

    看数据范围像是个暴力,而且理论复杂度似乎可行,然后被卡了两个点...然后来了个乱搞的线段树+扫描线.. 3225: [Sdoi2008]立方体覆盖 Time Limit: 2 Sec Memory L ...

  7. hdu 5091(线段树+扫描线)

    上海邀请赛的一道题目,看比赛时很多队伍水过去了,当时还想了好久却没有发现这题有什么水题的性质,原来是道成题. 最近学习了下线段树扫描线才发现确实是挺水的一道题. hdu5091 #include &l ...

  8. POJ1151+线段树+扫描线

    /* 线段树+扫描线+离散化 求多个矩形的面积 */ #include<stdio.h> #include<string.h> #include<stdlib.h> ...

  9. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

  10. HDU 5107 线段树扫描线

    给出N个点(x,y).每一个点有一个高度h 给出M次询问.问在(x,y)范围内第k小的高度是多少,没有输出-1 (k<=10) 线段树扫描线 首先离散化Y坐标,以Y坐标建立线段树 对全部的点和询 ...

随机推荐

  1. Java中DAO/DTO/PO/VO/BO/QO/POJO

    ORM:是Object Relational Mapping(对象关系映射)的缩写. 通俗点讲,就是将对象与关系数据库绑定,用对象来表示关系数据.在O/R/M的世界里,有两个基本的也是重要的东东需要了 ...

  2. ZFS

    zfs是128bit文件系统,那么为什么容量是2^64byte? 不应该是2^128 / 2^3=2^125 byte吗 文件系统不再局限于单独的物理设备,而且文件系统还允许物理设备把他们自带的那些文 ...

  3. apache2 ubuntu18.04 配置虚拟端口

    修改3个文件/etc/apache2/apache2.conf/etc/apache2/ports.conf/etc/apache2/sites-available/000-default.conf ...

  4. 从理论到实践,全方位认识DNS(理论篇)

    对于 DNS(Domain Name System) 大家肯定不陌生,不就是用来将一个网站的域名转换为对应的IP吗.当我们发现可以上QQ但不能浏览网页时,我们会想到可能是域名服务器挂掉了:当我们用别人 ...

  5. vmware9.0 install ubuntu

    1)安装vmware 9.0  + 注册码2)因为是.bundle文件,执行下列命令:sudo chmod +x VMware-Workstation-7.1.1-282343.i386.bundle ...

  6. requireJS defined undefined

    requeireJS 在使用时,在 defined 注入一个依赖,路径正确,却发现获得的值却是 undefined .这时候就要考虑是否是“循环依赖”的原因了. 循环依赖就是: a.js 依赖了 b. ...

  7. 利用rman自己主动备份转储spfile

    利用rman自己主动备份转储spfile [情景简单介绍] 生产环境丢失了server的參数文件,rman已开启自己主动备份设置. [操作过程简述] ----启动rman $rman target / ...

  8. 从头认识java-13.7 什么时候使用泛型?

    这一章节我们来讨论一下什么时候使用泛型? 答案:当你希望代码能够跨多个类型(不同的类型,不包括继承关系)工作的时候. 1.当没有确切类型的时候 以下是错误的代码: package com.ray.ch ...

  9. Uva 10036 - Divisibility

    Consider an arbitrary sequence of integers. One can place + or - operators between integers in the s ...

  10. imagebutton 设置了src属性的图片更换

    <ImageButton android:id="@+id/mediacontroller_play_pause" android:layout_width="wr ...