[POJ]3277.City Horizon

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;
        }//if
        intervalTree[num].cover = 1;
        return;
    }//if
    // 当前节点的左子节点所代表的线段包含插入的线段
    if(right <= intervalTree[num].mid){
        Insert(left,right,height,2*num);
    }//if
    // 当前节点的右子节点所代表的线段包含插入的线段
    else if(left >= intervalTree[num].mid){
        Insert(left,right,height,2*num+1);
    }//if
    // 插入的线段跨越了当前节点所代表线段的中点
    else{
        Insert(left,intervalTree[num].mid,height,2*num);
        Insert(intervalTree[num].mid,right,height,2*num+1);
    }//else
}

而最后计算面积并时,需要遍历整个线段树,因为这样才能确定每个从根节点到叶节点的路径上,即每个元线段上(形如[a,a+1)的线段),最大的高度是多少。统计过程从根向叶遍历,遍历过程中统计高度的最大值,并在叶节点上进行计算,非叶节点的计算结果是其左右子节点的计算结果之和。实现的代码如下(因为计算结果的数据超过了int的范围,所以使用long long 数据类型):

// 计算面积
long long Cal(int h,int num){
    // 统计过程从根向叶遍历,遍历过程中统计高度的最大值
    if(h > builds[num].height){
        builds[num].height = h;
    }//if
    // 叶节点上进行计算
    if(builds[num].left + 1 == builds[num].right){
        long long area = builds[num].height *
        (hash[builds[num].right] - hash[builds[num].left]);
        return area;
    }//if
    // 非叶节点的计算结果是其左右子节点的计算结果之和
    return Cal(builds[num].height,2*num) +
    Cal(builds[num].height,2*num+1);
}
时间: 2024-08-02 05:55:07

[POJ]3277.City Horizon的相关文章

POJ 2312Battle City(BFS-priority_queue 或者是建图spfa)

/* bfs搜索!要注意的是点与点的权值是不一样的哦! 空地到空地的步数是1, 空地到墙的步数是2(轰一炮+移过去) 所以用到优先队列进行对当前节点步数的更新! */ #include<iostream> #include<queue> #include<cstring> #include<algorithm> #include<cstdio> using namespace std; int n, m; char map[305][305];

数据结构专题

打星号的表示个人认为比较经典,或是算法比较好的题目   1195 Mobile phones 树状数组 1455 1521 Entropy huffman 1703 Find them, Catch them 并查集 1785 Binary Search Heap Construction 1794 Castle Walls 逆序对 1961 Period KMP重复因子 1984* Navigation Nightmare 并查集+坐标平移 1986* Distance Queries LCA

深入探讨POJ 2312 Battle City 优先队列+BFS_C 语言

相信坦克大战大家都玩过吧,本题就是根据这个游戏设计的.坦克要从起点(Y),到目的地(T),坦克不能通过钢墙(S),河(R),可以在空地在行走(E),射击破坏砖墙(B),射击砖墙时不行走且花费一个单位的时间,在空地上行走时也花费一个单位的时间.求坦克从起点到目的地最少花多少时间,不可达输出-1:很好的一道搜索题.因为考虑到通过砖墙时和空地所花的时间不同,所以不能使用一般的BFS广搜来做.用DFS深搜,你会发现时间复杂非常高,必然会超时(最大是300*300的图).本题可以使用改进过的广搜或优先队列

poj 1703 Find them, Catch them:种类并查集

链接: http://poj.org/problem?id=1703 题目: Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 22289   Accepted: 6648 Description The police office in Tadu City decides to say ends to the chaos, as launch actions to root up

SEERC 2004 / UVa 1330 City Game (扫描)

1330 - City Game Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=460&page=show_problem&problem=4076 Bob is a strategy game programming specialist. In his new city building game the ga

POJ题目分类

初期: 一.基本算法:      (1)枚举. (poj1753,poj2965)      (2)贪心(poj1328,poj2109,poj2586)      (3)递归和分治法.      (4)递推.      (5)构造法.(poj3295)      (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996) 二.图算法:      (1)图的深度优先遍历和广度优先遍历.      (2)最短路径算法(dijkstra,bellman-ford

POJ:DNA Sorting 特殊的排序

Description One measure of ``unsortedness'' in a sequence is the number of pairs of entries that are out of order with respect to each other. For instance, in the letter sequence ``DAABEC'', this measure is 5, since D is greater than four letters to

POJ 1001 Exponentiation 无限大数的指数乘法 题解

POJ做的很好,本题就是要求一个无限位大的指数乘法结果. 要求基础:无限大数位相乘 额外要求:处理特殊情况的能力 -- 关键是考这个能力了. 所以本题的用例特别重要,再聪明的人也会疏忽某些用例的. 本题对程序健壮性的考查到达了变态级别了. 更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/ 某人贴出的测试用例数据地址: http://poj.org/showmessage?message_id=76017 有

POJ 2240 Arbitrage:最短路 Floyd

Arbitrage:http://poj.org/problem?id=2240 大意: 给你m种货币,给你m种货币兑换规则,问通过这些规则最后能不能盈利.eg:1美元换0.5英镑,1英镑换10法郎,1法郎换0.21美元,这样1美元能换0.5*10*0.21=1.05美元,净赚0.05美元. 思路: 用Floyd找出每两种钱之间的最大兑换关系,遍历一遍,看有没有那种钱币最后能盈利,有就输出Yes,没有就是No.在处理钱币名称与编号之间的关系时,可以用map存(比较好用),当然也可以用字符串比较.