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. 让你忘记 Flash 的15款精彩 HTML5 游戏

    HTML5 游戏开发是一个热门的话题,开发人员和设计人员最近经常谈论到.虽然不能迅速取代 Flash 的地位,但是 HTML5 凭借它的开放性和强大的编程能力,取代 Flash 是必然的趋势.你会看到 ...

  2. Ionic – 强大的 HTML5 Mobile App 开发框架

    Ionic 是一个强大的 HTML5 应用程序开发框架,可以帮助您使用 Web 技术,比如 HTML.CSS 和 Javascript 构建接近原生体验的移动应用程序.Ionic 主要关注外观和体验, ...

  3. 【干货分享】32本优秀的 JavaScript 免费电子书

    JSbooks 收集了32本优秀的 JavaScript 免费电子书,分为初级.中级.高级三个类比,大家可以根据自身的情况需要下载.实实在在的干货!记得收藏和分享啊:) 您可能感兴趣的相关文章 Ver ...

  4. [deviceone开发]-直播APP心形点赞动画示例

    一.简介 这个示例展示do_Animator组件的简单使用,通过点击"点赞"按钮,不断弹出心形图片,向上动画漂移到顶部消失.间隔时间和上下左右移动的步长都是一定范围的随机值. 二. ...

  5. html5标签的改变

    1.新的文档类型声明 浏览器解析html模式是有两种模式,按照各自浏览器的定义渲染的页面叫“怪异模式”,而按照w3c组织统一的标准渲染叫“标准模式”.一般都是使用标准模式来保持网页兼容性,区分这两种模 ...

  6. [ javascript canvas isPointInPath(x,y) 判断点是否在最后绘制的图形中 ] javascript canvas isPointInPath(x,y) 判断点是否在最后绘制的图形中方法演示 效果之三

    <!DOCTYPE html> <html lang='zh-cn'> <head> <title>Insert you title</title ...

  7. 关于SharPoint2013一点细节的深究

    在进行SharePoint2013的开发过程中我发现在开启了某些功能,或者说是创建了个人站点之后有很多地方变了比如下面这个地方:     当然相应的URL地址也发生改变.也许很明确的我就打开了Welc ...

  8. Android通过PHP服务器实现登录

    Android客户端和PHP.MySQL搭建的服务器之间的简单交互,实现登录功能 . 实现原理图: Handler消息机制原理: Handler机制主要包括4个关键对象,分别是Message.Hand ...

  9. 使用imeOptions

    Android的软键盘右下角有Action按钮,如下图的“上一步” 在EditText中有 android:imeOptions选项,它包括完成按钮“actionDone”,发送按钮“actionSe ...

  10. Xcode8如何去除控制台多余的打印信息

    Xcode8如何去除控制台多余的打印信息 最近刚使用了Xcode8.遇到了一些问题,总结如下.希望对大家有所帮助. 一.如何去除控制台多余的打印信息. 方法:点击Product----Scheme-- ...