【题解】P4119 [Ynoi2018] 未来日记

题意

P4119 [Ynoi2018] 未来日记

给定一个长度为 n 的序列和 m 个操作,每次操作可以:

  1. [l,r] 内的所有值 x 改为值 y

  2. 查询 [l,r] 内第 k 小的值

相同的值算多次。

1n,m,ai105

思路

最初分块。

分块 + 值域分块 + 并查集。

显然思路是二分套树状数组求静态 k 小值,但是复杂度不对。

考虑用值域分块代替二分。

将值域 [1,105] 分成 105 块。

sum1i,j 表示前 i 个块内,在第 j 个值域块内的值的个数,sum2i,j 表示前 i 个块内值 j 的个数。这两个数组可以 O(nn) 预处理。

询问散块直接暴力 nth_element

询问 [l,r] 时另外处理 cnt1i 表示散块内在第 i 个值域块内的值的个数,cnt2i 表示散块内值 i 的个数。当块长取 n 时,处理这两个数组复杂度是 O(n)

假设询问第 k 小。

首先确定第 k 小值所处的值域块。具体实现可以令 sum 初始为 0,枚举值域块 i 时令 sum 不断累加 [l,r] 内第 i 个值域块内的值的个数(用上面处理的数组 O(1) 求),当 sumk 时说明第 k 小值在第 i 个值域块内。枚举值域块复杂度是 O(n)

然后枚举值域块内的值,用类似上面的方法求出第 k 小值。复杂度也是 O(n)

类似于 P4117 [Ynoi2018] 五彩斑斓的世界,维护 rti,j,vali,j,posirti,j=k 表示 k 是第 i 个块内值 j 对应并查集的根,vali,j=k 表示第 i 个块内根 j 对应的值为 k。令 beli 表示下标 i 所属的块的编号,则 pos[i] = rt[ bel[i] ][ a[i] ]

小优化,并查集的根编号不必用数组下标。

ai 的真实值为 val[ bel[i] ][ pos[i] ],还原序列直接用。

直接修改很难,不妨先用 sum1sum2 差分出每块内的答案,对每块答案单独维护,最后再前缀和合并。显然不影响复杂度。

散块直接暴力修改重构即可,复杂度是 O(n)

修改整块 i 可以分成三种情况:

  • i 内无 x,跳过;

  • i 内有 xy,令 rt[i][y] = rt[i][x], val[i][ rt[i][x] ] = y, rt[i][x] = 0,相应修改 sum1sum2

  • i 内有 xy。显然序列中出现过的不同值个数最多为 n+m,这种情况下每次块内值的个数会减少 1,暴力重构均摊总复杂度是 O((n+m)n),直接暴力即可

时间复杂度 O((n+m)n)

代码

posted @   kymru  阅读(227)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
主题色彩