2995 楼房

 时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 黄金 Gold
 
 
 
题目描述 Description

地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i])。地平线高度为0。在轮廓线长度最小的前提下,从左到右输出轮廓线。

输入描述 Input Description

第一行一个整数n,表示矩形个数

以下n行,每行3个整数h[i],l[i],r[i]表示第i个矩形。

输出描述 Output Description

第一行一个整数m,表示节点个数

以下m行,每行一个坐标表示轮廓线上的节点。从左到右遍历轮廓线并顺序输出节点。第一个和最后一个节点的y坐标必然为0。

样例输入 Sample Input

【样例输入】

2
3 0 2
4 1 3

【样例输入2】

5
3 -3 0
2 -1 1
4 2 4
2 3 7
3 6 8

样例输出 Sample Output

【样例输出】

6
0 0
0 3
1 3
1 4
3 4
3 0

【样例输出2】

14
-3 0
-3 3
0 3
0 2
1 2
1 0
2 0
2 4
4 4
4 2
6 2
6 3
8 3
8 0

数据范围及提示 Data Size & Hint

对于30%的数据,n<=100

对于另外30%的数据,n<=100000,1<=h[i],l[i],r[i]<=1000

对于100%的数据,1<=n<=100000,1<=h[i]<=10^9,-10^9<=l[i]<r[i]<=10^9

 /*-----------------------------正确的题解---------------------------------*/
/*扫描线+堆
我们把每一个楼房的两边(墙壁)的信息记录下来,然后按照墙壁的横坐标排序(具体方法见代码)
,当扫到楼房左边时,如果它是最高的,就把答案记录下来,否则入堆,
扫到楼房右边时,如果它与当前最高的一样高并且最高的只有一条线,记
录答案,删除对它对应的左边墙壁,否则删除左边墙壁信息,不进行其他操作。 */
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
#define N 100100
struct ss{
int h,l,r;
bool operator < (const ss &a) const{
if(l==a.l) return h>a.h;//双关键字排序
return l<a.l;
}
}e[N<<];
struct node{
int h,r;
node(ss x){h=x.h,r=x.r;}
bool operator < (const node &a) const{
return h<a.h;/*按照高度排序是为了满足覆盖关系*/
}
};
int n,cnt;//记录点的个数
pair<int,int>ans[N<<];//记录答案点的坐标,这个空间要开到n*4,因为可能有比较极端的情况,使每个矩形的两边都形成解
priority_queue<node>que;//大根堆
ss bfs(ss now,int x){//更新now,处理记录扫描后的矩形的右端点
while(!que.empty()){
node nown=que.top();que.pop();
if(nown.r>now.r){//有比它宽的,且比它矮的
if(nown.h!=now.h) ans[++cnt]=make_pair(now.r,now.h),ans[++cnt]=make_pair(now.r,nown.h);
now.r=nown.r;now.h=nown.h;
}
if(now.r>=x) return now;//*
}
//队列空说明:有断层
ans[++cnt]=make_pair(now.r,now.h),ans[++cnt]=make_pair(now.r,);//断层左边的两个点
now.h=;now.r=0x7fffffff;//now.h清零,now.r=inf为的是覆盖全区间,在*处起作用
return now;
}
void solve(){
ans[++cnt]=make_pair(e[].l,);ans[++cnt]=make_pair(e[].l,e[].h);//记录左边界答案
ss now=e[];
for(int i=;i<=n;i++){//总共分 ①②③ 三大情况,前两种比较直观,第三种比较难处理
if(now.h>=e[i].h&&now.r>=e[i].l) que.push(e[i]);//① 存入堆,做备用最高点(这里处理了包含的情况)
if(now.h<e[i].h&&now.r>=e[i].l){//②
que.push(now);//把比当前最高点低的点都存入堆,一个也不能漏
ans[++cnt]=make_pair(e[i].l,now.h);//较低点
now=e[i];
ans[++cnt]=make_pair(e[i].l,now.h);//较高点
}
if(now.r<e[i].l){//③
now=bfs(now,e[i].l);//判断一个矩形横穿e[i]这个矩形
if(now.h>=e[i].h&&now.r>=e[i].l) que.push(e[i]);
if(now.h<e[i].h&&now.r>=e[i].l){//断层和比他低的一起处理
que.push(now);//上边的now=bfs..和这里很好的处理了输出点坐标的顺序问题
ans[++cnt]=make_pair(e[i].l,now.h);
now=e[i];
ans[++cnt]=make_pair(e[i].l,now.h);
}
}
}
bfs(now,0x7fffffff);//遍历全区间做收尾工作:因为最后一个点的右边界不一定是所有元素的最右边界
//总结:只要最高点发生跃迁,就要记录答案
}
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d%d%d",&e[i].h,&e[i].l,&e[i].r);
sort(e+,e+n+);//左端点升序排列
solve();
printf("%d\n",cnt);
for(int i=;i<=cnt;i++) printf("%d %d\n",ans[i].first,ans[i].second);//因为记录是按顺序记录的,所以按顺序输出即可
return ;
}

一开始没做过扫描线的题目,毫无思路。感觉情况很多。不好考虑,线段树又忘记怎么打了。只拿了特殊数据的30分。

这个题目的思路还是敢于大胆的一个一个的合并矩形,同时把合并中的所有情况都考虑到,这样就能AC了。

我的代码:

 #define N 100100
#include<iostream>
using namespace std;
#include<cstdio>
#include<queue>
#include<algorithm>
int n;
struct Jx{
int h,l,r;
bool operator <(Jx P)
const{
return h<P.h;
}
}jx[N<<];
priority_queue<Jx>Q;
int anssum=;
pair<int,int>ans[N<<];
bool cmp(Jx Q,Jx P)
{
if(Q.l<P.l) return true;
if(Q.l>P.l) return false;
return Q.h>P.h;
}
void input()
{
scanf("%d",&n);
for(int i=;i<=n;++i)
scanf("%d%d%d",&jx[i].h,&jx[i].l,&jx[i].r);
}
Jx bfs(Jx now,int x)
{
Jx nown;
while(!Q.empty())
{
nown=Q.top();
Q.pop();
if(now.r<nown.r)
{
if(now.h!=nown.h)
{
ans[++anssum]=make_pair(now.r,now.h);
ans[++anssum]=make_pair(now.r,nown.h);
}
now=nown;
}
if(now.r>=x) return now;
}
ans[++anssum]=make_pair(now.r,now.h);
ans[++anssum]=make_pair(now.r,);
now.l=now.r;
now.h=;
now.r=(<<)-;
return now;
}
void solve()
{
ans[++anssum]=make_pair(jx[].l,);
ans[++anssum]=make_pair(jx[].l,jx[].h);
Jx now=jx[];
for(int i=;i<=n;++i)
{
if(jx[i].h<=now.h&&jx[i].l<=now.r)
{
Q.push(jx[i]);
}
if(jx[i].h>now.h&&jx[i].l<=now.r)
{
Q.push(now);
ans[++anssum]=make_pair(jx[i].l,now.h);
ans[++anssum]=make_pair(jx[i].l,jx[i].h);
now=jx[i];
}
if(now.r<jx[i].l)
{
now=bfs(now,jx[i].l);
if(jx[i].h<=now.h&&jx[i].l<=now.r)
{
Q.push(jx[i]);
}
if(jx[i].h>now.h&&jx[i].l<=now.r)
{
Q.push(now);
ans[++anssum]=make_pair(jx[i].l,now.h);
ans[++anssum]=make_pair(jx[i].l,jx[i].h);
now=jx[i];
}
}
}
bfs(now,(<<)-);
}
int main()
{
input();
sort(jx+,jx+n+,cmp);
solve();
printf("%d\n",anssum);
for(int i=;i<=anssum;++i)
printf("%d %d\n",ans[i].first,ans[i].second);
return ;
}

扫描线+堆 codevs 2995 楼房的更多相关文章

  1. codevs 2995 楼房

    /*暴力30分*/ #include<iostream> #include<cstring> #include<cstdio> #include<map> ...

  2. AC日记——楼房 codevs 2995

    2995 楼房  时间限制: 1 s  空间限制: 256000 KB  题目等级 : 黄金 Gold 题解  查看运行结果     题目描述 Description 地平线(x轴)上有n个矩(lou ...

  3. 楼房 洛谷1382 && codevs2995

    P1382 楼房 题目描述 地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i],0),右上角为(r[i],h[i]).地平 ...

  4. 【2016福建省夏令营Day1】数据结构

    Problem 1 楼房(build.cpp/c/pas) [题目描述] 地平线(x轴)上有n个矩(lou)形(fang),用三个整数h[i],l[i],r[i]来表示第i个矩形:矩形左下角为(l[i ...

  5. [日常训练]FJ省夏令营day1

    T1 Description 给出n个矩形的顶点坐标(每个矩形的底边都在x轴上),求这n个矩形所组成图形的轮廓线的顶点. Input 第一行一个整数n,表示矩形个数. 以下n行,每行3个整数,分别表示 ...

  6. OI总结(垃圾排版就忽略了吧)

    学OI一年了,到现在联赛所需要的知识已经基本学完了.现在,有必要回过头来,总结总结自己一年来学到的知识以及得到的经验教训. 基础 语言基础 C++的语言基础啥的就略了吧. 算法复杂度分析 O:复杂度的 ...

  7. luogu P1904 天际线

    分析 都知道是从左向右扫描 可是该维护什么,扫描什么? 注意想想怎么输出, 实际上它要的输出就是图形的轮廓,即每个突出块的左上节点的x,y 所以说, 我们可以把扫描线扫进的楼房放入线段树,扫出的楼房删 ...

  8. Codevs堆练习

    Codevs堆练习 黄金:2830.2879.2995.3110 钻石:1052.1063.1245.1246.2057.2573.3377 大师:1021.1765.2069.2913.3032

  9. codevs 2879 堆的判断

    codevs 2879 堆的判断 http://codevs.cn/problem/2879/ 题目描述 Description 堆是一种常用的数据结构.二叉堆是一个特殊的二叉树,他的父亲节点比两个儿 ...

随机推荐

  1. ABAP语言常用的系统字段及函数

    常用的系统变量如下: 1. SY-PAGNO当前页号 2. SY-DATUM当前时间 3. SY-LINSZ当前报表宽度 4. SY-LINCT当前报表长度 5. SPACE空字符 6. SY-SUB ...

  2. SharePoint 2010 站点附加数据升级到SP2013

    首先,去SharePoint 2010的数据库服务器上,找到站点的数据库,备份.还原到SharePoint 2013环境中: 如果不知道数据库服务器是哪台,可以通过服务器场上的服务器查看: 如果不知道 ...

  3. sharepoint:找不到位于 http://XX.XX.XX.XX 的 Web

    自己写了个sharepoint的webservice,发不到IIS上后报错: System.IO.FileNotFoundException: 找不到位于 http://XX.XX.XX.XX 的 W ...

  4. iOS使用Charles(青花瓷)抓包并篡改返回数据图文详解

    写本文的契机主要是前段时间有次用青花瓷抓包有一步忘了,在网上查了半天也没找到写的完整的教程,于是待问题解决后抽时间截了图,自己写一遍封存在博客园中以便以后随时查阅. charles又名青花瓷,在iOS ...

  5. struts理解

    最近大家都在找工作,我好迷茫,觉得自己会的东西太少了.所以决定开始学习SSH三大框架. 首先是struts. struts是基于mvc模式的框架.(struts其实也是servlet封装,提高开发效率 ...

  6. C语言32个关键字

    auto   局部变量(自动储存) break无条件退出程序最内层循环 case   switch语句中选择项 char单字节整型数据 const定义不可更改的常量值 continue中断本次循环,并 ...

  7. mac PHP配置

    apache默认路径配置方法 apache的配置   apache已经自带了,只需如下三个命令就可以了. 开启apache服务 sudo apachectl start 停止apache服务 sudo ...

  8. Linux Shell 网络层监控脚本(监控包括:连接数、句柄数及根据监控反馈结果分析)

    脚本监控: 获取最大句柄数的进程: 链接分析: 脚本片段: case "$handle" in 2) echo "The handle of the process : ...

  9. RPM方式安装MySQL5.5.48 (Aliyun CentOS 7.0 & 卸载MySQL5.7)

    环境是阿里云的CentOS7.0,更新了yum源(更新yum源请参考https://help.aliyun.com/knowledge_detail/5974184.html)之后先是尝试安装了MyS ...

  10. CentOS vsftp安装与配置

    详细配置说明:. http://www.cnblogs.com/app-lin/p/5189762.html 1.安装vsftpd yum install vsftpd 2.启动/重启/关闭vsftp ...