[POJ] 3277 .City Horizon(离散+线段树)
来自这两篇博客的总结
http://blog.csdn.net/SunnyYoona/article/details/43938355
http://m.blog.csdn.net/blog/mr_zys/10226425
题目大意
如图所示,在一条水平线上有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)的空间内对其进行处理了。这就是离散化的威力。
回到原问题上来,当矩形所投影的线段被离散化以后,我们就可以建立线段树了。与之前讲过的初始化略有不同,现在每个线段树的节点不只是记录其所代表的线段是否被覆盖,而且要记录被覆盖的线段的权值。每次加入一个矩形就是在线段树上插入一条带权的线段,插入的实现过程与之前的也有不同。如果当前线段完全覆盖了节点所代表的线段,那么比较这两个线段的权值大小。如果节点所代表的线段的权值小或者在之前根本未被覆盖,则将其权值更新为当前线段的权值。
#include <stdio.h>
#include <algorithm>
using namespace std; #define maxn 40400
int max_h[maxn*];
int line[maxn<<];
struct buildings
{
int a;
int b;
int h;
} B[maxn];
void build(int l,int r,int rt)
{
max_h[rt] = ;
if(l + == r) return;
int mid = (l + r) >> ;
build(l,mid,rt<<);
build(mid,r,rt<<|);
}
void update(int l,int r,int rt,int L,int R,int h)
{
if(line[l] == L && line[r] == R) //若插入的线段完全覆盖当前节点所表示的线段
{
max_h[rt] = max(max_h[rt],h);
return ;
}
int m = (l + r) >> ;
int mid = line[m];
if(R <= mid) update(l,m,rt<<,L,R,h);// 当前节点的左子节点所代表的线段包含插入的线段
else if(L >= mid) update(m,r,rt<<|,L,R,h); // 当前节点的右子节点所代表的线段包含插入的线段
else // 插入的线段跨越了当前节点所代表线段的中点
{
update(l,m,rt<<,L,mid,h);
update(m,r,rt<<|,mid,R,h);
}
}
long long solve(int l,int r,int rt,int h)
{
//如果rt结点的值大,那么rt的子孙结点都是该值
if( h > max_h[rt]) max_h[rt] = h;
if(l + == r) return (long long) (line[r] - line[l]) * max_h[rt];
int mid = (l + r) >> ;
return solve(l,mid,rt<<,max_h[rt]) + solve(mid,r,rt<<|,max_h[rt]);
}
int main()
{
int n,cnt;
scanf("%d",&n);
cnt = ;
for(int i = ; i < n; i++)
{
scanf("%d%d%d",&B[i].a,&B[i].b,&B[i].h);
line[++cnt] = B[i].a;
line[++cnt] = B[i].b;
}
sort(line+,line++cnt);
cnt = unique(line+,line++cnt) - line -;//离散处理
build(,cnt,);
for(int i = ; i < n; i++) update(,cnt,,B[i].a,B[i].b,B[i].h);
printf("%lld\n",solve(,cnt,,));
return ;
}
[POJ] 3277 .City Horizon(离散+线段树)的更多相关文章
- POJ 3277 City Horizon(扫描线+线段树)
题目链接 类似求面积并..2Y.. #include <cstdio> #include <cstring> #include <string> #include ...
- 离散化+线段树 POJ 3277 City Horizon
POJ 3277 City Horizon Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 18466 Accepted: 507 ...
- POJ 3277 City Horizon(叶子节点为[a,a+1)的线段树+离散化)
网上还有用unique函数和lowerbound函数离散的方法,可以百度搜下题解就有. 这里给出介绍unique函数的链接:http://www.cnblogs.com/zhangshu/archiv ...
- poj 3277 City Horizon (线段树 扫描线 矩形面积并)
题目链接 题意: 给一些矩形,给出长和高,其中长是用区间的形式给出的,有些区间有重叠,最后求所有矩形的面积. 分析: 给的区间的范围很大,所以需要离散化,还需要把y坐标去重,不过我试了一下不去重 也不 ...
- POJ 3277 City Horizon
标题效果: 每间房子的长度给出阴影(在间隔代表)而高度,求阴影总面积. 解题思路:矩形面积并. 以下是代码: #include <set> #include <map> #in ...
- POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化)
POJ.2528 Mayor's posters (线段树 区间更新 区间查询 离散化) 题意分析 贴海报,新的海报能覆盖在旧的海报上面,最后贴完了,求问能看见几张海报. 最多有10000张海报,海报 ...
- (中等) POJ 2528 Mayor's posters , 离散+线段树。
Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral electio ...
- poj 2528 Mayor's posters 线段树区间更新
Mayor's posters Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://poj.org/problem?id=2528 Descript ...
- POJ 2528 Mayor's posters(线段树+离散化)
Mayor's posters 转载自:http://blog.csdn.net/winddreams/article/details/38443761 [题目链接]Mayor's posters [ ...
随机推荐
- [Jquery]瀑布流
$(window).load(function(e){ waterfall(); var dataInt={'data':[{'src':'1.jpg'},{'src':'2.jpg'}, ...
- 在Linux中查看文件的编码及对文件进行编码转换
如果你需要在Linux中操作windows下的文件,那么你可能会经常遇到文件编码转换的问题.Windows中默认的文件格式是GBK(gb2312),而Linux一般都是UTF-8.下面介绍一下,在Li ...
- python开发规则
1.Python优点:简单.优雅.明确 python缺点 2.强大的模块三房库 1.代码不能加密 3.易移植 2.速度慢 4.面向对象 5.可扩展(c\java\c#....) cpython ipy ...
- (DFS)hdoj1312-Red and Black
题目链接 非常简单的DFS,初学DFS做这道题很合适.需要注意的是题目中输入的行和列顺序是颠倒的. #include<cstdio> #include<cstring> usi ...
- EntityFramework查询oracle数据库时报ora-12704: character set mismatch
1.这段linq,执行期间报ora-12704:character set mismatch错误. var query = from m in ctx.MENU where (m.SUPER_MENU ...
- CodeForces 546A-Soldier and Bananas
题意: 有n dollar,the first banana cost k dollars,第i个就需cost k*i,问买w个bananas是否需要借钱:借钱需要多少? 分析:首先计算w个bana ...
- java udp网络编程
import java.net.*; /* 通过UDP传输发送文字数据 1.建立socket服务 2.提供数据,并封装到数据包中 3.通过sokect服务的发送功能,将数据包发送出去 4.关闭资源 * ...
- Qt之控件美化
级联样式表 (CSS) 包含应用于网页中的元素的样式规则.CSS 样式定义元素的显示方式以及元素在页中的放置位置.可以创建一个通用规则,只要 Web 浏览器遇到一个元素实例,或遇到一个分配给某个特定样 ...
- Notification通知栏
Notification通知栏 首先实现的功能就是通知栏显示Notification,Notification是显示在系统的通知栏上面的,所以Notification 是属于进程之前的通讯.进程之间的 ...
- (转)mysql账号权限密码设置方法
原文:http://www.greensoftcode.net/techntxt/2013410134247568042483 mysql账号权限密码设置方法 我的mysql安装在c:\mysql 一 ...