题目描述

地平线(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. 大数据de 2文章

    点击可免费试用网易有数 文章来源:网易有数的搭积木原则阐述 ,经作者文雯授权发布 wo ceceshi 相关文章:[推荐] SpringBoot入门(五)--自定义配置

  2. javascript的优美与鸡肋

    --总结来自:<javascript语言精粹> 任何语言都有其优美的地方和其鸡肋的地方.避归一些语言的糟粕,能相应的降低bug出现的几率. 优美处: 函数是头等对象 基于原型继承的动态对象 ...

  3. C++怎么用二维数组作为形参传入

    原文地址:http://blog.csdn.net/xuleicsu/article/details/919801 如何将二维数组作为函数的参数传递 今天写程序的时候要用到二维数组作参数传给一个函数, ...

  4. 解决灰色shader与mask冲突的方案

    Shader "Custom/Opaque" { Properties { [PerRendererData] _MainTex ("Sprite Texture&quo ...

  5. Python全栈 MongoDB 数据库(聚合、二进制、GridFS、pymongo模块)

    断网了2天  今天补上     聚合操作: 对文档的信息进行整理统计的操作 返回:统计后的文档集合 db.collection.aggregate() 功能:聚合函数,完成聚合操作 参数:聚合条件,配 ...

  6. 问题 A: Least Common Multiple

    题目描述 The least common multiple (LCM) of a set of positive integers is the smallest positive integer ...

  7. LeetCode - 38. Count and Say(36ms)

    The count-and-say sequence is the sequence of integers with the first five terms as following: 1. 1 ...

  8. 第一周 Introduction

    欢迎 欢迎来到这门关于机器学习的免费网络课程,机器学习是近年来最激动人心的技术之一,在这门课中,你不仅可以了解机器学习的原理,更有机会进行实践操作,并且亲自运用所学的算法. 每天你都可能在不知不觉中使 ...

  9. Halcon和Opencv区别

    Halcon:机器视觉行业里知名的商业视觉库,非开源的,在国内市场份额处于第一,其提供了1500个多个API算子供开发人员使用,有些编程基础的都可以轻松的入门,其调试也是很方便的,断点单步运行,图像变 ...

  10. 第5讲——cin处理字符输入

    本来这一讲应该是while.for.if之类的,但是,我们可是学过C的男人,再浪费时间搞这个??? 还不如学点C++中的新知识. cin对象支持3种不同模式的单字符输入,其用户接口各不相同. 下面我们 ...