题目描述

地平线(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. Python字符串处理:过滤字符串中的英文与符号,保留汉字

    使用Python 的re模块,re模块提供了re.sub用于替换字符串中的匹配项. re.sub(pattern, repl, string, count=0) 参数说明: pattern:正则重的模 ...

  2. LeetCode:3.Longest Substring Without Repeating Characters

    思路:看到题目首先想到最大字符串匹配KMP算法 public static int lengthOfLongestSubstring(String s) { int maxLength = 0; St ...

  3. Deep Learning 之 最优化方法

    Deep Learning 之 最优化方法 2017年05月21日 22:18:40 阅读数:5910 写在前面本文主要是对Deep Learning一书最优化方法的总结,具体详细的算法,另起博文展开 ...

  4. Scala学习笔记(一):环境搭建

    计算机领域的编程语言种类繁多,如C.C++.Java.C#等,我们知道的一般都是较为流行的编程语言,然有更多的是没听说过的,于是也就说不上关注或者使用了 一次在网上查资料时,无意间看到了“函数式编程” ...

  5. es2017中的async和await要点

    1. async和await最关键的用途是以同步的写法实现了异步调用,是对Generator异步方法的简化和改进.使用Generator实现异步的缺点如下: 得有一个任务执行器来自动调用next() ...

  6. 【廖雪峰老师python教程】——错误和调试

    错误处理 try...except...finally...机制 try: print('try...') r = 10 / 0 print('result:', r) except ZeroDivi ...

  7. Qt QML之不显示标题栏、边框

    原文连接:http://blog.csdn.net/u010780613 我使用的Qt版本是Qt 5.3.0,Qt Creator 是3.1.1. QML做界面实在太方便了,动画效果很不错. 创建一个 ...

  8. 序列化反序列化--Xstream的使用

    之前讲了fastjson的使用--将JavaBean与json对象之间互相转换. 该篇文章,教大家使用Xstream来实现XMl与JavaBean的转换. 第一步: 通过maven引入XStream的 ...

  9. 第十九章 Python os模块,pathlib 判断文件是目录还是文件

    OS模块 os.path.abspath() :返回path规范化的绝对路径 import sys import os BASE_DIR = os.path.dirname(os.path.dirna ...

  10. LB

    LB(LBaaS)及Load Balance as a Service是 Neutron 提供的一项高级网络服务. LBaaS 允许租户在自己的网络中创建和管理 load balancer,load ...