楼房重建
题目链接:https://www.luogu.com.cn/problem/P4198
题目大意:维护有多少个不同的前缀最大值(相同数值但是位置更靠后的认为更大且两数不同,即认为每个数字加上与位置成正比的浮动)
做法
非常经典的题目,众所周知,信息学有一类题目的出题方法就是打破常规。
这道题目就是个经典的打破常规的题目,当然你也可以从别的角度去看他。
正常的线段树 updata 都是 $O(1)$ 的,但是这道题目的 updata 是 $\log$ 的。
更详细的来说,维护这么一个函数 $g(x,k)$ ,能够维护 $x$ 所管理的区间中 $\ge k$ 的不同前缀最大值个数。
这个函数可以 $\log$ ,当左区间的最大值 $<k$ ,那么直接去右区间,左区间贡献为 $0$ 。否则,说明考虑左区间的话,对右区间的不同前缀最大值没有影响,直接去左区间就行了,而右区间的贡献就是 $x$ 的不同前缀最大值个数,减去左儿子的。(满足可减性)
用这个函数可以在 $\log$ 的时间轻松实现 updata ,这样就可以在 $O(\log^2)$ 的时间解决这个问题。
显然,这个做法还能轻松实现区间不同的前缀最大值个数。
时间复杂度: $O(n+q\log^2n)$ 。
空间复杂度: $O(n)$ 。
1 |
|
当然,这个问题还能扩展。
思考一下,假如维护的信息不满足可减性怎么办呢?
答案是每个点不维护区间的答案,而是维护在考虑左区间的情况下右区间的贡献即可。
这个方法又有个别名,叫兔队线段树。
原链接在这:https://www.cnblogs.com/PinkRabbit/p/Segment-Tree-and-Prefix-Maximums.html
一道练习题在这:https://codeforces.com/contest/671/problem/E
具体做法看原链接吧,我感觉粉兔已经说的很明白了。其实是因为我懒