P3712 少女与战车

我永远喜欢数据结构。

P5356 由乃打扑克加强版。看了神仙 @5k_sync_closer 的题解发现 \(len\le 10\) 可以忽略,是不是爆标了!5k 好闪,拜谢 5k!

果然根号数据结构照样可爱。

题目传送门

  • 给出 \(n\) 个点的有根树,定义一个点的深度为它到根简单路径上的边权和。有 \(m\) 次操作,每次询问子树内第 \(k\) 小的深度,或是讲某条边权值加 \(k\)

  • \(n,m\le 10^5\)

  • \(\text{3 s / 500 MB}\)

设值域为 \(V\)。默认 \(\mathcal{O}(\log n)=\mathcal{O}(\log|V|)\)

首先将子树拍平成 \(dfn\) 序,则问题就是区间加、查区间 \(k\) 小值。考虑分块,设块长为 \(B\)

对于整块,维护初始数组 \(a\)、加标记 \(tag\) 以及排序后的数组 \(c\)。记 \(i\) 所在块为 \(bel_i\),我们要实时维护 \(a_i+tag_{bel_i}\)\(i\) 这个位置的真实值,且对于一个整块的下标区间 \([l,r]\)\(c_l\sim c_r\)\(a_l\sim a_r\) 排序后的结果。

修改时,整块修改标记、散块暴力重构。查询时,二分答案,然后求区间内有多少个小于等于它的数。

算法一

  • 修改时,暴力枚举整块标记加 \(k\),暴力枚举散块使用 std::stable_sort 重构散块。单次时间复杂度为 \(\mathcal{O}\left(B\log n+\dfrac{n}{B}\right)\)

  • 查询的二分答案时,设二分的值为 \(mid\),散块暴力枚举,整块在排序的数组上二分最后一个真实值不超过 \(mid\) 的位置。然后块的起点到这个位置的数都要被统计。单次时间复杂度为 \(\mathcal{O}\left(\left(\dfrac{n}{B}\log n+B\right)\log n\right)\)

  • \(B=\mathcal{O}\left(\sqrt{n\log n}\right)\) 时,时间复杂度为 \(\mathcal{O}\left(n+m\sqrt{n\log n}\log n\right)\)。无法接受。

  • 空间复杂度为 \(\mathcal{O}(n)\)

算法二

  • 修改时,整块仍然暴力标记加 \(k\)。考虑将散块的 \(c\) 数组对应的区间 \([l,r]\) 分成两个子序列:一个子序列内的原数下标不在本次修改的区间内,另一个则在。对于这两个子序列而言,它们都是单调非降的。可以归并排序。这样一来,单次时间复杂度变为 \(\mathcal{O}\left(B+\dfrac{n}{B}\right)\)

  • 二分答案时,对于散块仍然采用类似的方式归并成一个长度为 \(\mathcal{O}(B)\) 的有序数组。不需要暴力枚举,直接在数组上二分。整块查询方式不变。这样查询时间复杂度为 \(\mathcal{O}\left(\left(\dfrac{n}{B}\log n+\log B\right)\log n\right)\)

  • \(B=\mathcal{O}\left(\sqrt{n}\log n\right)\) 时,时间复杂度为 \(\mathcal{O}\left(n+m\sqrt{n}\log n\right)\) 可以接受。

  • 空间复杂度为 \(\mathcal{O}(n)\)

  • AC 记录

  • AC 代码

更多算法

P5356 题解区提到了时间复杂度 \(\mathcal{O}\left(n+m\sqrt{n\log n}\right)\)\(\mathcal{O}\left(n+m\sqrt{n}\right)\)(好像有,可能是我看错了)的做法,空间复杂度不清楚。膜拜 DS 大神们,我这个数据结构萌新爬了。

posted @ 2024-02-21 17:36  lzyqwq  阅读(27)  评论(0编辑  收藏  举报