题目大意:

小A在平面上(0,0)点的位置,第i栋楼房可以用一条连接(i,0)和(i,Hi)的线段表示,其中Hi为第i栋楼房的高度。如果这栋楼房上任何一个高度大于0的点与(0,0)的连线没有与之前的线段相交,那么这栋楼房就被认为是可见的。

施工队的建造总共进行了M天。初始时,所有楼房都还没有开始建造,它们的高度均为0。在第i天,建筑队将会将横坐标为Xi的房屋的高度变为Yi(高度可以比原来大—修建,也可以比原来小—拆除,甚至可以保持不变—建筑队这天什么事也没做)。请你帮小A数数每天在建筑队完工之后,他能看到多少栋楼房?

分析:

显然可以想到进行斜率处理,通过斜率的单调递增来求出len。

其实答案就是整个1—n区间中从第一项开始,每一个大于前一项的必选,小于等于前一项的必须不选,所的得到的序列长度。

因为区间是固定的,并且发现一个区间内的答案可以通过两个子区间用某种方式进行转移。所以可以考虑到线段树做法。

线段树中只需要维护两个值,一个是区间最大值,还有一个是区间序列长度(按照刚才的理解)的值。

建树(甚至不用),修改,甚至不用pushdown,一切好说。但是发现pushup不好处理,显然两个子区间的值不能直接合并。必须满足一定关系。

可以发现,区间内的第一项一定在这个序列内,区间最大值也一定在这个序列内。

对于要被pushup的区间,它的两个子区间已经处理好了,容易知道,左儿子区间内的序列每一项一定都在这个大区间内。(因为前面形态固定,又不能选择不看到)所以只需要处理右儿子区间和左儿子区间最大值的关系,即可递归处理len值。

递归要传入该区间的值必须大于的最小值,设为lx。对于开始进入时,也就是左儿子的最大值。

1.如果l==r,该位置的值大于lx,return1,否则return0;

2.将该区间劈成两段,设为s1,s2区间。

①如果s1的最大值小于等于lx,那么s1必然不会对答案产生贡献,去找s2。即代码中: return pushup2(lx,s2,mid+1,r)

②如果s1的最大值大于lx,那么s2中剩下的在s1,s2组成的原区间中做贡献的项一定能贡献到最终答案中。即+l(x)-l(s1),这里注意,不是 l(s2),因为可能在l(s2)中存在的项,不一定在l(x)这个大区间中出现。所以这两个值是完全不同的概念。

之后再去寻找s1. 即:return pushup2(lx,s1,l,mid)+l(x)-l(s1);

核心代码:

int pushup2(double lx,int x,int l,int r)
{
if(m(x)<=lx) return ;//剪枝
if(a[l]>lx) return l(x);//剪枝
if(l==r) return a[l]>lx;//①
int s1=x<<,s2=x<<|;
int mid=(l+r)>>;
if(m(s1)<=lx) return pushup2(lx,s2,mid+,r);//②
else return pushup2(lx,s1,l,mid)+l(x)-l(s1);//③
}

详见代码:

#include<bits/stdc++.h>
using namespace std;
const int N=+;
int n,m;
double a[N];
struct node{
double mx;
int len;
#define m(x) t[x].mx
#define l(x) t[x].len
}t[*N];
void pushup1(int x)
{
m(x)=max(m(x<<),m(x<<|));
}
int pushup2(double lx,int x,int l,int r)
{
if(m(x)<=lx) return ;
if(a[l]>lx) return l(x);
if(l==r) return a[l]>lx;
int s1=x<<,s2=x<<|;
int mid=(l+r)>>;
if(m(s1)<=lx) return pushup2(lx,s2,mid+,r);
else return pushup2(lx,s1,l,mid)+l(x)-l(s1);
}
void chan(int x,int l,int r,int to,int c)
{
if(l==r&&l==to)
{
m(x)=(double)c/to;
l(x)=;
return ;
}
int mid=(l+r)>>;
if(to<=mid) chan(x<<,l,mid,to,c);
else if(to>mid) chan(x<<|,mid+,r,to,c);
pushup1(x);
l(x)=l(x<<)+pushup2(m(x<<),x<<|,mid+,r);
}
int main()
{
scanf("%d%d",&n,&m);
int x,y;
for(int i=;i<=m;i++)
{
scanf("%d%d",&x,&y);
a[x]=(double)y/x;
chan(,,n,x,y);
printf("%d\n",t[].len);
}
return ;
}

总结:

1.其实这个题就是把pushup logn化,是pushup一种难度升级版。

2.只要可以想办法区间合并的问题,都可以尝试用线段树解决。虽然有时候一看看不出来。

luogu P4198 楼房重建——线段树的更多相关文章

  1. [Luogu P4198]楼房重建(线段树)

    题目描述 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些事件发生在一个 ...

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

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

  3. Luogu P4198 楼房重建 (李超线段树)

    题目 传送门 题解 首先转化成到(0,0)(0,0)(0,0)的斜率. 那么就是求多少个点是前缀最大值. 做法是线段树,用gao(i,x)gao(i,x)gao(i,x)表示在iii区间内,之前最大值 ...

  4. Luogu P4198 楼房重建 分块 or 线段树

    思路:分块 提交:2次(第一次的求解有问题) 题解: 设块长为$T$,我们开$N/T$个单调栈,维护每一块的上升斜率. 修改时暴力重构整个块,$O(T)$ 求解时记录一个最大斜率$lst$,然后块内二 ...

  5. luogu题解P4198楼房重建--线段树神操作

    题目链接 https://www.luogu.org/problemnew/show/P4198 分析 一句话题意,一条数轴上有若干楼房,坐标为\(xi\)的楼房有高度\(hi\),那么它的斜率为\( ...

  6. [BZOJ29957] 楼房重建 - 线段树

    2957: 楼房重建 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 3294  Solved: 1554[Submit][Status][Discus ...

  7. bzoj 2957: 楼房重建 线段树

    2957: 楼房重建 Time Limit: 10 Sec  Memory Limit: 256 MB[Submit][Status][Discuss] Description 小A的楼房外有一大片施 ...

  8. 【题解】Luogu P4198 楼房重建

    原题传送门 根据斜率来建线段树,线段树维护区间最大斜率以及区间内能看见的楼房的数量(不考虑其他地方的原因,两个节点合并时再考虑) 细节见程序 #include <bits/stdc++.h> ...

  9. bzoj 2957: 楼房重建 ——线段树

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

随机推荐

  1. MySQL主主同步配置

    1. MySQL主主配置过程 在上一篇实现了主从同步的基础上,进行主主同步的配置. 这里用node19(主),node20(从)做修改,使得node19和node20变为主主同步配置模式 修改配置文件 ...

  2. Mongodb副本集+分片集群环境部署记录

    前面详细介绍了mongodb的副本集和分片的原理,这里就不赘述了.下面记录Mongodb副本集+分片集群环境部署过程: MongoDB Sharding Cluster,需要三种角色: Shard S ...

  3. "Linux内核分析"第七周

    可执行程序的装载 张文俊+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.预 ...

  4. ☆C++学习心得

    C++是我进大学的学的第一种编程语言,在高中的时候有电脑课,有教过部分的VB语言,所以其实对编程也并不是非常的陌生,刚开是上课也觉得感觉不难,都懂,没多少课后,恍了个神..居然听不懂了!老师经常让我们 ...

  5. 必应语音API(Bing text to speech API)

    前言 Link : Microsoft Speech API overview 通过这个链接,大致了解Bing speech API的语音识别和语音合成两部分, 这次是需要用到TTS,所以就直接看TT ...

  6. WIN10 评估版 查看过期时间

    命令行运行winver,弹出的窗口显示过期时间,如 下图: 又可以再用一段时间教育版了,本机预装的的家庭版序列号,还没法从教育版降级到家庭版,可悲吧(win7时代就不允许从高级降低到低级用啊)

  7. node多文件处理方法

    let events = require('events'); let fs = require('fs'); // 将readfile封装成一个方法 多文件处理  function fnreadFi ...

  8. Linux下安装oracle的过程

    1. Linux 安装 主要不要将home分区设置的特别大 2. 安装必须的一些包. yum install -y \ binutils.x86_64 \ elfutils-libelf-devel. ...

  9. (一) 关于配置travis-ci持续集成python pytest测试的相关记录

    首先由于公司用上了高大上的travis-ci商用版,一直想试着学学弄弄看.现在要写openapi的相关测试,而且要在travis-ci上集成.我就想体验一下这个过程.所以自己弄了一个public的仓库 ...

  10. Centos7安装Splash

    前言 最近在用Scrapy抓取一个网站数据,其中有个页面需要执行js脚本才能加载,所以需要用到Splash. 官网地址:https://splash.readthedocs.io/en/stable/ ...