Description
Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouettes formed by the rectangular buildings.
The entire horizon is represented by a number line with N (1 ≤ N ≤ 40,000) buildings. Building i’s silhouette has a base that spans locations Ai through Bi along the horizon (1 ≤ Ai < Bi ≤ 1,000,000,000) and has height Hi (1 ≤ Hi ≤ 1,000,000,000). Determine the area, in square units, of the aggregate silhouette formed by all N buildings.
Input
Line 1: A single integer: N
Lines 2..N+1: Input line i+1 describes building i with three space-separated integers: Ai, Bi, and Hi
Output
Line 1: The total area, in square units, of the silhouettes formed by all N buildings
Sample Input
4
2 5 1
9 10 4
6 8 2
4 6 3
Sample Output
16
Hint
The first building overlaps with the fourth building for an area of 1 square unit, so the total area is just 3*1 + 1*4 + 2*2 + 2*3 - 1 = 16.
Source
USACO 2007 Open Silver
题目大意
如图所示,在一条水平线上有N个建筑物,建筑物都是长方形的,且可以互相遮盖。给出每个建筑物的左右坐标值Ai,Bi以及每个建筑物的高Hi,需要计算出这些建筑物总共覆盖的面积。
题目数据范围:
建筑物个数N:1 <= N <= 40000
建筑物左右坐标值Ai, Bi:1 <= Ai,Bi <= 10^9
建筑物的高度Hi:1 <= Hi <= 10^9
分析
由题意可以知道,这道题需要求的即是这些矩形的面积并。考虑到题目中一个特殊的条件,所有的矩形的一边在一条直线上,我们可以好好利用这个条件:由于所有的矩形在这条直线上的投影均与矩形的一个边长相等。所以,我们可以把矩形“压缩”成直线上的线段,且每条线段都有一个权值,这个权值就是矩形的高度Hi。那么,我们就可以利用线段树进行处理,计算面积并就相当于计算带权的线段并,即S = H * (B – A)。当某条线段被多次覆盖时(比如图中的线段A2B1),只取H值最大的进行计算。如图2.1中的矩形面积并为:S = H1*(B1 – A1) + H2 * (A3 – B2) + H3 * (B3 – A3) 基本思路清楚了,我们现在来考虑具体实现。
由于题目中矩形的左右坐标的范围非常大(1 <= Ai,Bi <= 10^9),如果建立大小为[1, 10^9)的线段树则会占用大量的空间。我们采用一种离散化的思想来处理这个问题,这种思路在线段树的题目中也是经常会用到的。考虑到一共只有N <= 40000个矩形,那么,这些矩形一共也只有2 * 40000 = 80000个左右坐标值。我们首先将这80000个坐标值按大小排序,对排序后的坐标依次赋予一个新坐标值k(1 <= k <= 80000),这样我们就把长度为[1, 10^9)的线段离散化成[1,80000)的线段了,而最后计算结果时,只需要按照新坐标值找回原始坐标值并代入计算即可。
举一个简单的例子,假设现在有三条线段[20,60),[10,50),[5,55)。我们将这三条线段的左右端点进行排序,其结果为5,10,20,50,55,60。我们将它们依次赋上新值1,2,3,4,5, 6。这样原始的三条线段被离散化为[3,6),[2,4),[1,5),我们就可以在[1,6)的空间内对其进行处理了。这就是离散化的威力。
回到原问题上来,当矩形所投影的线段被离散化以后,我们就可以建立线段树了。与之前讲过的初始化略有不同,现在每个线段树的节点不只是记录其所代表的线段是否被覆盖,而且要记录被覆盖的线段的权值。每次加入一个矩形就是在线段树上插入一条带权的线段,插入的实现过程与之前的也有不同。如果当前线段完全覆盖了节点所代表的线段,那么比较这两个线段的权值大小。如果节点所代表的线段的权值小或者在之前根本未被覆盖,则将其权值更新为当前线段的权值。
void Insert(int left,int right,int height,int num){
if(intervalTree[num].left == left && intervalTree[num].right == right){
if(intervalTree[num].height < height){
intervalTree[num].height = height;
}
intervalTree[num].cover = 1;
return;
}
if(right <= intervalTree[num].mid){
Insert(left,right,height,2*num);
}
else if(left >= intervalTree[num].mid){
Insert(left,right,height,2*num+1);
}
else{
Insert(left,intervalTree[num].mid,height,2*num);
Insert(intervalTree[num].mid,right,height,2*num+1);
}
}
而最后计算面积并时,需要遍历整个线段树,因为这样才能确定每个从根节点到叶节点的路径上,即每个元线段上(形如[a,a+1)的线段),最大的高度是多少。统计过程从根向叶遍历,遍历过程中统计高度的最大值,并在叶节点上进行计算,非叶节点的计算结果是其左右子节点的计算结果之和。实现的代码如下(因为计算结果的数据超过了int的范围,所以使用long long 数据类型):
long long Cal(int h,int num){
if(h > builds[num].height){
builds[num].height = h;
}
if(builds[num].left + 1 == builds[num].right){
long long area = builds[num].height *
(hash[builds[num].right] - hash[builds[num].left]);
return area;
}
return Cal(builds[num].height,2*num) +
Cal(builds[num].height,2*num+1);
}
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
相关推荐
问题:求平面上多个矩形的总面积。 算法:线段树(经典的线段树题目)
POJ2943.dsw希望有用 下载,下载!!!
ACM题目分析与解答(POJ).rar ACM题目分析与解答(POJ).rar
poj2801.dsw 下载,下载!!!
poj.grids.cn题型汇总 Dp状态设计与方程总结 1.不完全状态记录 青蛙过河问题 利用区间dp 2.背包类问题 <1> 0-1背包,经典问题 无限背包,经典问题 判定性背包问题 带附属关系的背包问题 <5> + -1背包问题 ...
poj 2820 古代密码 http://poj.grids.cn/problem?id=2820 可直接运行
详细解释 ,既有源代码又有书面文字解释,ppt,在VC6上完成
poj2880 输入一个英文句子,长度不超过40个字符。编写程序,输出句子中最长的一个单词。 http://poj.grids.cn/problem?id=2880 可直接运行
http://poj.grids.cn/problem?id=2774 POJ 2774 木棒加工 木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头,需要得到的小段的数目是给定了。当然,我们希望得到的小段越长越好,你的任务是计算能够...
问题:移动矩形方块,使其到达目标位置 算法:宽搜,因为方块为矩形,所以要处理好其落点问题
北大POJ第1324题(C++)
只是poj上的一条题目,对于理解后缀数组很有帮助.poj3261
POJ1753 Flip Game题目完整代码及报告
在进行ACM编程训练时做字符串专题的一些题目(POJ1782,POJ1790,POJ1951,POJ2003,POJ2121)
poj3254的答案, 含有比较详细的注释
POJ1087的解题报告,内附详细源码和解题报告说明,有价值
poj题目2775文件子目录源代码,递归经典题目,
poj上第1990题目源码,用到了2个树状数组,这题数据结构是关键,想到了题目就很简单了
poj2823,使用线段树进行查询区域间最大最小值,线段树初步
北大POJ第1328题代码(C++)