题目描述

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

下图为样例2。

输入输出格式

输入格式:

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

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

输出格式:

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

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

输入输出样例

输入样例#1:

2
3 0 2
4 1 3
输出样例#1:

6
0 0
0 3
1 3
1 4
3 4
3 0
输入样例#2:

5
3 -3 0
2 -1 1
4 2 4
2 3 7
3 6 8
输出样例#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

说明

【数据范围】

对于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

先留一点思考的时间

题解:

题意就是给出一张图形的坐标 ,求出这张图中的拐点个数和坐标.

对于60%的数据,可以直接模拟加离散化. 用数组存下每一个X轴上的点的最高值,但是为什么要用离散化呢?

当遇到这样的情况时,代码就会出问题:

h[2]=3, h[3]=2,那么在循环扫过来时就不会处理(2,0)和(3,0),但这两个点是存在的,所以要用离散化,将一格坐标变为两格坐标:

这样的话循环只会多一点常数,但是答案能保证正确.

对于100%的数据:

可以用离散化加线段树扫描线.

离散化加线段树的方法与暴力相类似,用线段树加速了区间最值的修改与查询.

扫描线

将矩形的左右两边看作是一条线段,分别是一个矩形的入边和出边,然后通过排序确定遍历扫描线的顺序.这样就可以在O(nlogn)的时间复杂度内完成.

那么扫描线应该怎么排序呢?

我们用扫描线就是为了确定一个矩形的覆盖情况,然后找到图中的拐点.那么首先就应该是要按照X轴上的坐标进行排序.并且应该先扫入边,再扫出边,这样可以保证不会有什么鬼的奇怪的数据有左右边相同的矩形使得结果出问题. 在判断完前两种情况后,现在正在排序的两条线就同属于一种边(同为入边或出边),那么若是入边,则越高越容易挡住另一个矩形,就要放在前面才会使得更新一次答案时没有矩形被挡住.若是出边,则越低越容易被挡住,则要放在后面,这样就可以使得高的出边在后面被扫到,就可以保证在删除最后一条出边时更新答案没有矩形被挡住.

 bool cmpl(line a,line b){
if(a.x!=b.x) return a.x<b.x;
if(a.f!=b.f) return a.f<b.f;
if(a.f==) return a.h>b.h;
if(a.f==) return a.h<b.h;
}

然后在后面扫描的时候就直接用for循环遍历每一条扫描线.那么扫到一条扫描线就有两种情况:

  1. 属于入边,如果比当前最高值还要高,则出现了拐点,更新答案.
  2. 属于出边,如果高度为当前最大高度且该高度出边只有一条,则出现了拐点,更新答案.

这里记录当前已经加入扫描的矩形时用了一个STL容器:multiset.这个东西与set不同的地方体现在它可以存入相同的元素,且默认单调递增,那么对于这个题目的实现就提供了一个很好的帮助.

C++ STL MultiSet类成员函数列表如下:

begin() 返回指向第一个元素的迭代器

clear() 清除所有元素

count() 返回指向某个值元素的个数

empty() 如果集合为空,返回true

end() 返回指向最后一个元素的迭代器

equal_range() 返回集合中与给定值相等的上下限的两个迭代器

erase() 删除集合中的元素

find() 返回一个指向被查找到元素的迭代器

get_allocator() 返回多元集合的分配器

insert() 在集合中插入元素

key_comp() 返回一个用于元素间值比较的函数

lower_bound() 返回指向大于(或等于)某值的第一个元素的迭代器

max_size() 返回集合能容纳的元素的最大限值

rbegin() 返回指向多元集合中最后一个元素的反向迭代器

rend() 返回指向多元集合中第一个元素的反向迭代器

size() 多元集合中元素的数目

swap() 交换两个多元集合变量

upper_bound() 返回一个大于某个值元素的迭代器

value_comp() 返回一个用于比较元素间的值的函数

然后把答案存到数组里,根据题目要求输出.

下面是代码:

#include<bits/stdc++.h>
using namespace std;
const int N=; int n;
int cnt=;
int cnta=; struct line{
int x,h,f;
}l[N*]; struct answer{
int x,y;
}ans[N*]; int gi(){
int ans=,f=;char i=getchar();
while(i<''||i>''){if(i=='-')f=-;i=getchar();}
while(i>=''&&i<=''){ans=ans*+i-'';i=getchar();}
return ans*f;
} bool cmpl(line a,line b){
if(a.x!=b.x) return a.x<b.x;
if(a.f!=b.f) return a.f<b.f;
if(a.f==) return a.h>b.h;
if(a.f==) return a.h<b.h;
} int main(){
//freopen("Fort.in","r",stdin);
//freopen("Fort.out","w",stdout);
n=gi();
for(int i=,x,y,z;i<=n;i++){
x=gi(); y=gi(); z=gi();
l[++cnt].x=y; l[cnt].h=x; l[cnt].f=;
l[++cnt].x=z; l[cnt].h=x; l[cnt].f=;
}
sort(l+,l+cnt+,cmpl);
multiset <int> s; s.insert();
for(int i=;i<=cnt;i++){
int maxh=*s.rbegin();
if(l[i].f==){
if(l[i].h>maxh){
ans[++cnta].x=l[i].x; ans[cnta].y=maxh;
ans[++cnta].x=l[i].x; ans[cnta].y=l[i].h;
}
s.insert(l[i].h);
}
if(l[i].f==){
if(l[i].h==maxh&&s.count(maxh)==){
s.erase(maxh);
ans[++cnta].x=l[i].x; ans[cnta].y=l[i].h;
ans[++cnta].x=l[i].x; ans[cnta].y=*s.rbegin();
}
else s.erase(s.find(l[i].h));
}
}
cout<<cnta<<endl;
for(int i=;i<=cnta;i++)
printf("%d %d\n",ans[i].x,ans[i].y);
return ;
}

[洛谷P1382] 楼房的更多相关文章

  1. 洛谷P4198 楼房重建 (分块)

    洛谷P4198 楼房重建 题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题, ...

  2. 洛谷 P4198 楼房重建 题解

    题面 首先你要知道题问的是什么:使用一种数据结构,动态地维护以1为起点地最长上升子序列(把楼房的高度转化成斜率地序列)的长度: 怎么做?线段树! 我们在线段树上维护两个东西:1.这个区间内斜率的最大值 ...

  3. 洛谷P4198 楼房重建 单调栈+线段树

    正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...

  4. 洛谷P4198 楼房重建(线段树)

    题意 题目链接 Sol 别问我为什么发两遍 就是为了骗访问量 这个题的线段树做法,,妙的很 首先一个显然的结论:位置\(i\)能被看到当且仅当\(\frac{H_k}{k} < \frac{H_ ...

  5. 洛谷P4198 楼房重建

    题意:给定序列,每次修改一个值,求前缀最大值的个数. 解:线段树经典应用. 每个节点维护最大值和该区间前缀最大值个数. 发现我们不用下传标记,只需要合并区间. 需要实现一个函数int ask([l r ...

  6. 洛谷 P4198 楼房重建

    思路 此题可转化为以下模型 给定序列\(a[1...n]\),支持单点修改,每次求区间单调栈大小 \(n,Q\le 10^5\) 区间单调栈是什么呢?对于一个区间,建立一个栈,首先将第一个元素入栈,从 ...

  7. 楼房 洛谷1382 && codevs2995

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

  8. 洛谷1640 bzoj1854游戏 匈牙利就是又短又快

    bzoj炸了,靠离线版题目做了两道(过过样例什么的还是轻松的)但是交不了,正巧洛谷有个"大牛分站",就转回洛谷做题了 水题先行,一道傻逼匈牙利 其实本来的思路是搜索然后发现写出来类 ...

  9. 洛谷P1352 codevs1380 没有上司的舞会——S.B.S.

    没有上司的舞会  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond       题目描述 Description Ural大学有N个职员,编号为1~N.他们有 ...

随机推荐

  1. C语言RL78 serial bootloader和C#语言bootloader PC端串口通信程序

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 前段时间完成的hype ...

  2. HMM相关文章索引

    HMM相关文章索引 1条回复 HMM系列文章是52nlp上访问量较高的一批文章,这里做个索引,方便大家参考. HMM学习 HMM学习最佳范例一:介绍 HMM学习最佳范例二:生成模式 HMM学习最佳范例 ...

  3. 『MongoDB』集合更新操作

    参考 定义 db.collection.update(query, update, options) 改变一个在集合中已经存在的文档或文档数组.默认的,update()方法更新一个独立的文档.如果mu ...

  4. 怎么在windows10中关闭Windows Defender?

    通过修改注册表,永久禁用Windows Defender 打开注册表编辑器. 按 Win +R键入regedit,点击确定.    定位需要修改的注册表 其路径如下 HKEY_LOCAL_MACHIN ...

  5. Python 3基础教程28-内置函数

    本文介绍Python中的内置函数,Python中有很多内置的,功能强大的函数,可以帮我们解决很多问题,有些方法,根本不需要你去再次编写实现函数,你直接调用就可以.在这之前,需要介绍下,如何在windo ...

  6. GraphSAGE 代码解析(二) - layers.py

    原创文章-转载请注明出处哦.其他部分内容参见以下链接- GraphSAGE 代码解析(一) - unsupervised_train.py GraphSAGE 代码解析(三) - aggregator ...

  7. 目标检测之Faster-RCNN的pytorch代码详解(模型训练篇)

    本文所用代码gayhub的地址:https://github.com/chenyuntc/simple-faster-rcnn-pytorch  (非本人所写,博文只是解释代码) 好长时间没有发博客了 ...

  8. 团队项目-第十次scrum 会议

    时间:11.6 时长:20分钟 地点:主235教室走廊 工作情况 团队成员 已完成任务 待完成任务 解小锐 完成多种招聘方式的逻辑编写 陈鑫 实现游戏的存档功能 李金奇 添加多种招聘方式等功能 王辰昱 ...

  9. CubieTruck使用笔记--SD卡中使用lubuntu

    http://docs.cubieboard.org/tutorials/ct1/installation/install_lubuntu_desktop_server_to_sd_card 按照上面 ...

  10. Apache服务器的Options 的 Indexes FollowSymLinks详解

    禁止显示Apache目录列表 - Indexes FollowSymLinks 如何修改目录的配置以禁止显示 Apache 目录列表. 缺省情况下如果你在浏览器输入地址: http://localho ...