[BZOJ2957]楼房重建

貌似已经很久没有写blog了的说……一直在用为知笔记都快忘记博客了emm
这次先拿这样一道水题来写一下吧,这个思想好像很常用,最近这几天已经遇到很多次了。

题意

一个长度为 n n 的序列 wi w i 表示楼房高度,初始都是 0 0 ,有 m m 个操作,每次单点修改一个位置的高度,可以变成正的也可以变成负的,问有多少个位置能够在每次修改后被看到(也就是说,其最高点与原点连线上没有其他楼房)。
0n,m100000 0 ≤ n , m ≤ 100000

分析

题意非常明显,考虑维护每个高度对于原点的一个斜率 ki=wii k i = w i i ,这里要求的就是问有多少个 ki k i 大于前面所有数。这相当于就是在维护一个上升的单调序列,我们可以考虑用线段树来维护这个。
考虑每次直接查询整个区间,那么我们考虑对于某一个区间,我们可以记下这个区间只算自己内部应该有的答案,那么下面考虑一下怎么区间合并。考虑当前区间称为 [l,r] [ l , r ] ,那么左边的区间 [l,m] [ l , m ] 的答案肯定是可以直接算进来的,而右边的区间的答案则需要考虑加入左边区间的限制的情况下的新的答案。首先显然如果右区间斜率最大值小于等于左边最大值,那么右区间肯定没有贡献。
如果大于最大值,我们考虑这时怎么做。我们需要在右区间进一步分出其两个子区间来计算,同样的思想,我们只需要考虑一下左子区间会不会将这个左区间的影响“屏蔽”即可。如果左子区间最大值小于等于左区间最大值,就相当于左子区间整个没用了,我们递归处理右子区间;反之,说明左子区间里面存在至少一个点(例如那个最大值),会将左区间的影响全部“屏蔽”,那么递归处理左子区间即可。于是右区间的答案在后一种情况下就是整个区间的答案减去左子区间,因为单纯右子区间的答案并没有考虑左子区间的影响。
实际实现中,我们可以考虑写成“该节点对于某个值在最前面的答案”的查询。

你可能感兴趣的:(数据结构,bzoj,线段树)