二分上主席树与主席树上二分
二分上主席树
我们的主人公遇到了这样一个问题:给定一个长度为 \(n\) 的序列 \(a\),有 \(q\) 次查询,每次查询形如 \(l,r,k\),求满足 \(\sum\limits_{i=l}^r [a_i \leq v] \geq k\) 的最小 \(v\) 是多少。
这个时候聪明的小读者们就要说了:“\(v\) 显然是满足二分性的。可以直接二分一个 \(v\),然后使用主席树 check 它是否满足条件。”这是一个很好的做法。可以做到 \(O(n\log V\log n)\) 的时间复杂度,但是我谔谔,所以我们来讨论 \(O(n\log n)\) 的做法。
主席树上二分
这不是随便做吗?
显然地,此题有两种做法。第一种是,每一个值域前缀对应一棵主席树,想查 \(\sum\limits_{i=l}^r [a_i\leq v]\) 直接区间查就可以了(需要确定 \(v\)),但是显然,这样做只能做到 \(O(n\log V\log n)\)。
第二种是,每一个序列前缀对应一棵主席树。主席树上的节点存的就是一段值域区间内有多少个当前序列前缀中的值。容易发现,可以直接沿用普通线段树二分的方法做到 \(O(n\log n)\)。
为什么不同的建树方法会带来不同的时间复杂度呢?咨询了方面专家 M*****X 后,我得出了如下结论。
第一种,每棵主席树上存的是下标的出现次数,第二种,每棵主席树上存的是值的出现次数。而我们二分的东西就是值。发现,如果我们想二分的东西和主席树上存的东西一样,那么我们可以在一开始就确定查哪两棵主席树,然后在节点上时就能决策往左走还是往右走。也就是说,为了能实现主席树上二分,我们可能需要交换维度。
反正现在那个 T4 就可以做了吧。正常的贡献和刚刚一样是好算的,现在的问题是怎么 \(O(1)\) 求区间内第一个和最后一个 \(<Mid\) 的位置。反正就是我们可以维护一个 \(\leq r\) 的树和一个 \(\geq l\) 的树,分别把最小下标和最大下标求出来后看是否在区间里就行了。然后往下递归的时候一起算就没问题了。总而言之的时间复杂度是 \(O(n\log V)\) 吧。

浙公网安备 33010602011771号