题目大意

在平面上给定n个矩形,可以相互覆盖全部或者部分,求出矩形占据的总面积。

题目分析

将矩形按照x方向的进行分割之后,将平面沿着y方向划分一系列单元(不定高度),每个矩形在y方向上占据若干连续的单元;在x方向上,将矩形按照x坐标排序之后,考虑有一个扫描线从左到右扫描,当扫描线进入矩形之后,所有矩形在扫描线上占据的总长度有可能增加,而扫面线离开某个矩形时,所有矩形在扫描线上占据的总长度有可能减少。 
    在计算面积的时候,将当前扫描点 所有矩形在扫描线上占据的总长度 乘以 当前扫描点到下一扫描点的长度,直到所有矩形均出扫描线。区间操作,考虑使用线段树

实现(c++)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
#define MAX_RECT_NUM 1000
#define MAX_SEG_NUM MAX_RECT_NUM * 2
#define MAX_NODE_NUM 4*MAX_SEG_NUM
#define MAX(a, b) a > b? a :b
#define MIN(a, b) a < b? a :b
//根据矩形的上下边在y方向上划分区间单元(长度不固定),每个矩形占据y方向上的连续的几个单元,形成区间
struct Rect{
double top_left_x;
double top_left_y;
double bottom_right_x;
double bottom_right_y; int interval_beg; //在y轴上,该矩形所占据区间的起始单元序号
int interval_end; //在y轴上,该矩形所占据区间的结束单元序号(从下向上) inteval_beg 和 interval_end为 闭区间
}; Rect gRects[MAX_RECT_NUM];
vector<double> gPartPoint; //用于离散化的点纵坐标
vector<double> gSegs; //离散化之后的段单元长度 struct Node{
int beg; //在y轴方向离散化之后,节点所代表区间的起始块号
int end; //节点所代表区间的终止块号
double length; //节点所代表区间的长度(y轴方向)
int covered_num; //扫描线被多少个矩形覆盖
};
Node gNodes[MAX_NODE_NUM]; //对矩形进行x坐标从小到大排序,便于进行扫描
bool CmpToSortRect(const Rect& rect1, const Rect& rect2){
if (rect1.top_left_x == rect2.top_left_x)
return rect1.bottom_right_x < rect2.bottom_right_x;
return rect1.top_left_x < rect2.top_left_x;
} void BuildTree(int beg, int end, int index){
gNodes[index].beg = beg;
gNodes[index].end = end;
gNodes[index].covered_num = 0;
if (beg == end){
gNodes[index].length = gSegs[beg];
return;
}
int left = 2 * index + 1;
int right = 2 * index + 2;
int mid = (beg + end) / 2;
BuildTree(beg, mid, left);
BuildTree(mid + 1, end, right);
//由子节点长度得到父节点代表区间的长度
gNodes[index].length = gNodes[left].length + gNodes[right].length;
} //向下更新
void PushDown(int index){
if (gNodes[index].covered_num){
int left = 2 * index + 1, right = 2 * index + 2;
gNodes[left].covered_num += gNodes[index].covered_num;
gNodes[right].covered_num += gNodes[index].covered_num;
}
gNodes[index].covered_num = 0;
} //向上更新
void PushUp(int index){
int left = 2 * index + 1, right = 2 * index + 2;
int min = MIN(gNodes[left].covered_num, gNodes[right].covered_num);
gNodes[index].covered_num = min;
gNodes[left].covered_num -= min;
gNodes[right].covered_num -= min;
} //当扫描线进入矩形区域时step_in = true, 否则为false
void Update(int beg, int end, int index, bool step_in){
if (gNodes[index].beg >= beg && gNodes[index].end <= end){
if (step_in){
gNodes[index].covered_num++;
} else{
gNodes[index].covered_num--;
}
return;
}
if (gNodes[index].end < beg || gNodes[index].beg > end){
return;
}
if (beg > end){
return;
}
int left = 2 * index + 1, right = 2 * index + 2;
int mid = (gNodes[index].beg + gNodes[index].end) / 2;
//向下递归时,先pushdown 向下更新
PushDown(index);
Update(beg, MIN(mid, end), left, step_in);
Update(MAX(mid + 1, beg), end, right, step_in);
//递归返回进行 向上更新
PushUp(index);
} //查询,查询当前情况下,扫描线占据的矩形y方向长度
double Query(int index){
if (gNodes[index].covered_num > 0){
return gNodes[index].length;
}
if (gNodes[index].beg == gNodes[index].end){
return 0;
}
int left = 2 * index + 1, right = 2 * index + 2;
return Query(left) + Query(right);
} bool DoubleEqual(double d1, double d2){
if (abs(d1 - d2) < 1e-7){
return true;
}
return false;
}
int main(){
int n, cas = 1;
while (true){
scanf("%d", &n);
if (n == 0){
break;
}
gPartPoint.clear();
for (int i = 0; i < n; i++){
scanf("%lf %lf %lf %lf", &gRects[i].top_left_x, &gRects[i].top_left_y, &gRects[i].bottom_right_x, &gRects[i].bottom_right_y);
gPartPoint.push_back(gRects[i].top_left_y); //得到y方向上的各个离散的分界点
gPartPoint.push_back(gRects[i].bottom_right_y);
}
//对分界点进行排序,去重
sort(gPartPoint.begin(), gPartPoint.end());
vector<double>::iterator it = unique(gPartPoint.begin(), gPartPoint.end());
gPartPoint.erase(it, gPartPoint.end()); //根据分界点,得到离散化之后的区间长度
gSegs.clear();
gSegs.reserve(gPartPoint.size());
for (int i = 0; i < gPartPoint.size() - 1; i++){
double len = gPartPoint[i + 1] - gPartPoint[i];
gSegs.push_back(len);
} //得到每个矩形在y方向上占据的离散化之后的区间的 beg和end(闭区间)
for (int i = 0; i < n; i++){
vector<double>::iterator it = find(gPartPoint.begin(), gPartPoint.end(), gRects[i].top_left_y);
gRects[i].interval_beg = it - gPartPoint.begin();
it = find(gPartPoint.begin(), gPartPoint.end(), gRects[i].bottom_right_y);
gRects[i].interval_end = it - gPartPoint.begin() - 1;
} BuildTree(0, gSegs.size() - 1, 0); //将x方向的各个分割点进行排序,去重
gPartPoint.clear();
for (int i = 0; i < n; i++){
gPartPoint.push_back(gRects[i].top_left_x);
gPartPoint.push_back(gRects[i].bottom_right_x);
}
sort(gPartPoint.begin(), gPartPoint.end());
it = unique(gPartPoint.begin(), gPartPoint.end());
gPartPoint.erase(it, gPartPoint.end()); int seg_num = gSegs.size();
double sum_area = 0;
double height = 0;
int beg, end;
for (int i = 0; i < gPartPoint.size() - 1; i++){ for (int r = 0; r < n; r++){
if (DoubleEqual(gRects[r].top_left_x, gPartPoint[i])){ //扫描线进入矩形
Update(gRects[r].interval_beg, gRects[r].interval_end, 0, true);
}
if (DoubleEqual(gRects[r].bottom_right_x, gPartPoint[i])){//扫描线离开矩形
Update(gRects[r].interval_beg, gRects[r].interval_end, 0, false);
} }
height = Query(0);
sum_area += height*(gPartPoint[i + 1] - gPartPoint[i]);
}
printf("Test case #%d\n", cas ++);
printf("Total explored area: %.2lf\n\n", sum_area);
}
return 0;
}

poj_1151 线段树的更多相关文章

  1. bzoj3932--可持久化线段树

    题目大意: 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第 ...

  2. codevs 1082 线段树练习 3(区间维护)

    codevs 1082 线段树练习 3  时间限制: 3 s  空间限制: 128000 KB  题目等级 : 大师 Master 题目描述 Description 给你N个数,有两种操作: 1:给区 ...

  3. codevs 1576 最长上升子序列的线段树优化

    题目:codevs 1576 最长严格上升子序列 链接:http://codevs.cn/problem/1576/ 优化的地方是 1到i-1 中最大的 f[j]值,并且A[j]<A[i] .根 ...

  4. codevs 1080 线段树点修改

    先来介绍一下线段树. 线段树是一个把线段,或者说一个区间储存在二叉树中.如图所示的就是一棵线段树,它维护一个区间的和. 蓝色数字的是线段树的节点在数组中的位置,它表示的区间已经在图上标出,它的值就是这 ...

  5. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  6. PYOJ 44. 【HNSDFZ2016 #6】可持久化线段树

    #44. [HNSDFZ2016 #6]可持久化线段树 统计 描述 提交 自定义测试 题目描述 现有一序列 AA.您需要写一棵可持久化线段树,以实现如下操作: A v p x:对于版本v的序列,给 A ...

  7. CF719E(线段树+矩阵快速幂)

    题意:给你一个数列a,a[i]表示斐波那契数列的下标为a[i],求区间对应斐波那契数列数字的和,还要求能够维护对区间内所有下标加d的操作 分析:线段树 线段树的每个节点表示(f[i],f[i-1])这 ...

  8. 【BZOJ-3779】重组病毒 LinkCutTree + 线段树 + DFS序

    3779: 重组病毒 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 224  Solved: 95[Submit][Status][Discuss] ...

  9. 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集

    3673: 可持久化并查集 by zky Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 1878  Solved: 846[Submit][Status ...

随机推荐

  1. scp基本使用方法

    scp基本使用方法: scp用于在两台电脑之间进行数据的copy,形式如下:  第一种, scp [-r] 文件/文件夹  user@host:dir ,需要输入密码.  第二种, scp [-r] ...

  2. win7/win8下手工搭建WAMP环境

    win7/win8下手工搭建WAMP环境. 最近学习wamp,看了好多教程,出来好多问题,终于成功搞定,这里集合了一下最好的教程,写了一些自己的经验,希望大家有用 这里不能上传图片,我就写了个带pdf ...

  3. spring mvc 下载安装

    https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework ...

  4. imx6 android power off

    调试android4.2的关机功能,希望再按下power按键长时间之后就关机.不弹出选框. 参考链接 http://www.cnblogs.com/sardine/archive/2011/07/26 ...

  5. Can't connect to MySQL server on '192.168.7.175' (10060)

    原因: 1.你的ip没有被授权,无法访问. 2.端口没有打开(如:3306端口没有打开). 解决方法: 授权(http://www.cnblogs.com/SZxiaochun/p/6401424.h ...

  6. (转)Tiny210v2( S5PV210 ) 平台下 FIMD 对应 的 framebuffer 驱动中,关于 video buffer 的理解

    原文:http://www.arm9home.net/read.php?tid-25938.html 管理提醒: 本帖被 xoom 执行加亮操作(2012-12-13) 如之前所说,一直想知道显示数据 ...

  7. 平时收集的一些有关UED的团队和个人博客(转)

    UCDChina导航 前端团队 阿里巴巴 UED -- 我们设计的界面,并没有几十亿的流量,但每天来自上百个国家的百万商人在使用着. 阿里巴巴中国站UED -- 阿里巴巴中国站UED成立于1999年, ...

  8. opencv实例一:显示一张图片

    第一个简单的实例,显示一张图片: 1)代码如下 /*************************************************************************** ...

  9. Spring+Swagger文档无法排序问题解决

    项目中用到swagger用于自动生成文档,遇到了好多结合后的问题.而对于这个排序问题,在查看了后端Swagger原代码之后,发现视乎当前使用的swagger(不是springfox,应该不是官方的,网 ...

  10. Java基础-JDBC访问数据库

    基本步骤: 加载数据库驱动 建立连接 创建SQL语句 执行SQL语句 处理执行结果 释放资源 代码示例: import java.sql.Connection; import java.sql.Dri ...