[Ynoi2017] 由乃打扑克(区间第k小)

在这里插入图片描述
在这里插入图片描述

题目来源:P5356

题目描述很简单,就是区间修改,求区间第 k k k 小。

如果只是求区间第 k k k 小,我们可以使用整体二分,时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) ,也可以使用在值域主席树上二分,时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
如果带一个单点修改,我们还可以使用整体二分,把修改拆成两个赋值操作,时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n) ,当然也可以使用树套树来解决(但是我不会),时间复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)
但是如果是区间修改,整体二分和主席树就不太够用了,对于这种难搞的序列操作,考虑分块。

思路

先来思考一下如何查询区间第 k k k 小,我们考虑延续之前的风格------二分。具体而言,我们先二分出一个“第 k k k 小”,然后在这段区间内查找小于等于这个数的个数,如果小于 k − 1 k-1 k1 ,就往右继续二分,否则往左继续二分。
如何去查找区间内小于等于 x x x 的个数?这是分块的基本操作,块内排好序,小块暴力大块二分即可。

修改怎么做呢,对于整块,直接打个 t a g tag tag 整体加即可,对于散块,朴素的想法是暴力修改,之后块内重新排序。不过我们显然可以做到更优秀,因为我们原先的序列是有序地,所以我们修改的一段序列可以看做是有序地,没修改的序列也是有序的,两个有序地序列去排序,我们直接双指针即可。这样这部分的复杂度就可以少个 l o g log log

时间复杂度

修改的时间复杂度是 O ( m l o g N × ( B + n B ∗ l o g B ) ) O(mlogN\times(B+\frac{n}{B}*logB)) O(mlogN×(B+BnlogB)) ,其中 N N N 是值域, B B B 是块长。
查询的时间复杂度是 O ( m × ( n B + B ) ) O(m\times(\frac{n}{B}+B)) O(m×(Bn+B))
这时我们发现了一些问题,如果我们按照平常的做法取 B = n B=\sqrt n B=n ,那么修改的复杂度将来到惊人的 O ( m n   l o g N   l o g n ) O(m\sqrt n\,logN\,log\sqrt n) O(mn logNlogn )码了半天分块发现没 n 2 n^2 n2 ,怎么办呢?山穷水尽了吗?
但是我们转过头来看一下查询的复杂度,只有 O ( m n ) O(m\sqrt n) O(mn ) ,与修改严重不平衡,我们考虑如何将修改和查询的复杂度平衡。
听着好像很麻烦的样子,但其实很简单,我们只需要改一下块长即可,不要被 n \sqrt n n 的块长思想给固化了,本身 n \sqrt n n 的块长是因为这样取最优所以用的,但现在显然这个块长并不优秀,我们考虑更改一个本题最优秀的块长(理论上),显然,我们需要减少块的数量(也就是变大块长)从而平衡修改和查询,经过简单的计算,我们发现 B = n l o g n B=\sqrt n logn

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值