欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - POJ1151


题意概括

  给出n个矩形,求他们的面积并。

  n<=100


题解

  数据范围极小。

  我们分3种算法逐步优化。

  算法1: O(n3)

  如果这n个矩形的坐标都是整数,而且比较小,那么我们显然可以用最暴力的方法:一个一个打标记。

  但是不是这样的。

  坐标大小很大,而且是实数。

  然而我们发现差不多,只要先离散化一下,然后再打标记即可。

  算法2:O(n2)

  实际上,上面的方法十分慢。如果n的范围到了1000,上面的就无济于事了。

  而实际上,基于上面的打标记的算法,我们可以通过差分的方法n2解决。

  我们通过差分,可以用n2的时间标记,n2的时间判断每一个区域是否被覆盖。

  空间复杂度O(n2)

  算法3:O(n logn) 扫描线

  实际上,这类问题的数据范围可以到100000这个级别。

  矩形面积并可以用扫描线算法来解决。先看原理,后面讲具体实现。

  比如下图:

  

  当前我们的扫描线到达了淡黄色部分。

  由于之前没有记录,所以答案不增加。

  然而我们记下当前横向覆盖的长度。

  然后我们到了第二条扫描线,加上原来记录的横向覆盖长度乘以增加的高度就是当前增加的答案。

  然后,我们更新了横向覆盖的长度。

  继续。

  

  然后第三条。现在的横向覆盖长度是两边加起来,所以增加的面积是两块了。

  然后更新横向覆盖的长度,加上了中间的那一条。

  然后继续。

  

  现在有这么长的一条都是被横向覆盖的了。

  所以新增的面积是浅蓝色部分。

  然后我们发现左上那条线是出边,所以要删除这一条线。

  所以横向覆盖的长度为如下:

  

  同理,接下来是:

  

  然后就OK了。

  

  那么具体怎么实现呢?

  我们开一棵线段树来维护!

  在读入之后,我们把所有的横线都拆开,分成下边和上边两类。某一区间在进入下边的时候+1,离开上边的时候-1,所以我们分别给上下边标记+1和-1。

  对于Y,我们离散化一下。

  对于X,我们按照边的X排一个序。

  然后按照刚才那样的处理。

  具体如何维护详见代码。


代码

  1. #include <cstring>
  2. #include <algorithm>
  3. #include <cstdio>
  4. #include <cstdlib>
  5. #include <cmath>
  6. using namespace std;
  7. const int N=+,M=N*;
  8. const double Eps=1e-;
  9. int T=,n,m,tot_Y,tot_s;
  10. double Y[M];
  11. struct Segment{
  12. double x,L,R;
  13. int v;
  14. void set(double x_,double L_,double R_,int v_){
  15. x=x_,L=L_,R=R_,v=v_;
  16. }
  17. }s[M];
  18. struct SegTree{
  19. int cnt;
  20. double sum;
  21. }t[M*];
  22. bool cmp_s(Segment a,Segment b){
  23. return a.x<b.x;
  24. }
  25. void build(int rt,int le,int ri){
  26. t[rt].cnt=;
  27. t[rt].sum=;
  28. if (le==ri)
  29. return;
  30. int mid=(le+ri)>>,ls=rt<<,rs=ls|;
  31. build(ls,le,mid);
  32. build(rs,mid+,ri);
  33. }
  34. void pushup(int rt,int le,int ri){
  35. int ls=rt<<,rs=ls|;
  36. if (t[rt].cnt)
  37. t[rt].sum=Y[ri+]-Y[le];
  38. else if (le==ri)
  39. t[rt].sum=;
  40. else
  41. t[rt].sum=t[ls].sum+t[rs].sum;
  42. }
  43. void update(int rt,int le,int ri,int xle,int xri,int d){
  44. if (le>xri||ri<xle)
  45. return;
  46. if (xle<=le&&ri<=xri){
  47. t[rt].cnt+=d;
  48. pushup(rt,le,ri);
  49. return;
  50. }
  51. int mid=(le+ri)>>,ls=rt<<,rs=ls|;
  52. update(ls,le,mid,xle,xri,d);
  53. update(rs,mid+,ri,xle,xri,d);
  54. pushup(rt,le,ri);
  55. }
  56. int find_double(double x){
  57. int le=,ri=m,mid;
  58. while (le<=ri){
  59. mid=(le+ri)>>;
  60. if (abs(x-Y[mid])<Eps)
  61. return mid;
  62. if (Y[mid]<x)
  63. le=mid+;
  64. else
  65. ri=mid-;
  66. }
  67. }
  68. int main(){
  69. while (scanf("%d",&n)&&n){
  70. tot_Y=tot_s=;
  71. for (int i=;i<=n;i++){
  72. double xA,yA,xB,yB;
  73. scanf("%lf%lf%lf%lf",&xA,&yA,&xB,&yB);
  74. if (yB-yA<Eps||xB-xA<Eps)
  75. continue;
  76. Y[++tot_Y]=yA,Y[++tot_Y]=yB;
  77. s[++tot_s].set(xA,yA,yB,);
  78. s[++tot_s].set(xB,yA,yB,-);
  79. }
  80. sort(Y+,Y+tot_Y+);
  81. sort(s+,s+tot_s+,cmp_s);
  82. m=;
  83. for (int i=;i<=tot_Y;i++)
  84. if (Y[i]-Y[i-]>Eps)
  85. Y[++m]=Y[i];
  86. build(,,m);
  87. double ans=;
  88. for (int i=;i<=tot_s;i++){
  89. ans=ans+(s[i].x-s[i-].x)*t[].sum;
  90. int L=find_double(s[i].L);
  91. int R=find_double(s[i].R);
  92. update(,,m,L,R-,s[i].v);
  93. }
  94. printf("Test case #%d\nTotal explored area: %.2lf\n\n",++T,ans);
  95. }
  96. return ;
  97. }

POJ1151Atlantis 矩形面积并 扫描线 线段树的更多相关文章

  1. 矩形面积并-扫描线 线段树 离散化 模板-poj1151 hdu1542

    今天刚看到这个模板我是懵逼的,这个线段树既没有建树,也没有查询,只有一个update,而且区间成段更新也没有lazy标记....研究了一下午,我突然我发现我以前根本不懂扫描线,之所以没有lazy标记, ...

  2. POJ 1151 Atlantis 矩形面积求交/线段树扫描线

    Atlantis 题目连接 http://poj.org/problem?id=1151 Description here are several ancient Greek texts that c ...

  3. hdu1542 矩形面积并(线段树+离散化+扫描线)

    题意: 给你n个矩形,输入每个矩形的左上角坐标和右下角坐标. 然后求矩形的总面积.(矩形可能相交). 题解: 前言: 先说说做这道题的感受: 刚看到这道题顿时就懵逼了,几何 烂的渣渣.后来从网上搜题解 ...

  4. 【HDU 1542】Atlantis 矩形面积并(线段树,扫描法)

    [题目] Atlantis Problem Description There are several ancient Greek texts that contain descriptions of ...

  5. luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

    Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void ...

  6. HDU 1255 覆盖的面积 (扫描线 线段树 离散化 矩形面积并)

    题目链接 题意:中文题意. 分析:纯手敲,与上一道题目很相似,但是刚开始我以为只是把cnt>=0改成cnt>=2就行了,. 但是后来发现当当前加入的线段的范围之前 还有线段的时候就不行了, ...

  7. 【BZOJ4418】[Shoi2013]扇形面积并 扫描线+线段树

    [BZOJ4418][Shoi2013]扇形面积并 Description 给定N个同心的扇形,求有多少面积,被至少K个扇形所覆盖. Input 第一行是三个整数n,m,k.n代表同心扇形的个数,m用 ...

  8. (HDU 1542) Atlantis 矩形面积并——扫描线

    n个矩形,可以重叠,求面积并. n<=100: 暴力模拟扫描线.模拟赛大水题.(n^2) 甚至网上一种“分块”:分成n^2块,每一块看是否属于一个矩形. 甚至这个题就可以这么做. n<=1 ...

  9. HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)

    链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...

随机推荐

  1. HTML5的学习(二)HTML5标签

    3.按功能排列标签 (注:红色为HTML5不支持的,蓝色为HTML5新增的标签元素.)   3.1基本 标签 描述 HTML4 HTML5 <!--...--> 定义注释. √ √ < ...

  2. ACM-ICPC 2018 沈阳赛区网络预赛 K题

    题目链接: https://nanti.jisuanke.com/t/31452 AC代码(看到不好推的定理就先打表!!!!): #include<bits/stdc++.h> using ...

  3. 2018-2019-2 《网络对抗技术》Exp0 Kali安装 Week1 20165320

    下载源 Kali官网 下载安装过程是按照链接博客的操作完成的 虚拟机VMware安装Kali 安装成功截图 安装VM Tools 首先进入虚拟机,默认用户名为root,密码为安装过程中自己设置的. 在 ...

  4. 允许远程用户登录访问mysql的方法

    需要手动增加可以远程访问数据库的用户. 方法一.本地登入mysql,更改 "mysql" 数据库里的 "user" 表里的 "host" 项 ...

  5. linux关机时候执行命令脚本或程序

    Write a service file and place it in /etc/systemd/system/beforeshuttingdown.service code: [Unit] Des ...

  6. 红黑树与AVL树

    概述:本文从排序二叉树作为引子,讲解了红黑树,最后把红黑树和AVL树做了一个比较全面的对比. 1 排序二叉树 排序二叉树是一种特殊结构的二叉树,可以非常方便地对树中所有节点进行排序和检索. 排序二叉树 ...

  7. Qt5 json 数据处理

    QT4中使用第三方库QJson解析JSON文件. QT5新增加了处理JSON的类,类均以QJson开头,包含在QtCore模块中. 用到的头文件 #include <QJsonArray> ...

  8. web服务器tomcat入门实战

    一.tomcat介绍1.1 引入tomcat Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache.Su ...

  9. mysql数据库报错:InnoDB: Operating system error number 13 in a file operation

    环境:centos6.5 x86_64 启动mysql发现日志报错(日志路径可以查看/etc/my.cnf的配置) 160722 10:34:08 [Note] Found 42570716 of 4 ...

  10. Ex 6_18 硬币有限的兑换问题_第七次作业

    子问题定义: 定义一个二维数组b,其中b[i][j]表示前i个币种是否能兑换价格j,表示第i个币种的面值,第i个币种的使用有两种情况,若使用,则b[i][j]=b[i-1][j-],若不使用,则b[i ...