对了,200 blogs 祭。没想到是这么一篇揭露我大菜鸡水平的 blog。
主席树
一年前就学过了,到现在才开始系统学可持久化……都快要高一了才开始学这玩意,我真是 114514 流选手。
需要做的是,每次修改都不直接修改原来节点上的值,需要新建副本存下新值,使得可以任意访问任一历史版本。
这个就有这样一个思想:每次修改,不论是单点还是区间,由于复杂度被保证,只有对数级别的点被修改了。于是我们就把有修改的点给新建了,然后新建的所有点要连向不修改的原来节点,这些个节点在新旧版本中共用。脑补一下,单点的情况就是旁边多出来一条链,然后往里连。这样想要访问哪个版本,就从对应的根往下走即可。(烦死了说不清,会的都会)
需要注意的是,主席树区间修改不能用懒标记(因为往下推的时候可能会推到共用的儿子,就出锅了),只能标记永久化。
值得一题的是,主席树的空间是和动态开点一样分析的,是线对。如果按照原来的每个节点都额外存表示的区间的话,那可能会被卡,所以我做了一个伟大的决定:废除这个陋习!就递归往下走的时候顺便记录即可,还可以有效解决空节点没有存区间的问题。
模板:https://www.luogu.com.cn/record/47290779
可持久化数组
直接用主席树实现。
你可能要问,这数组既不需要区间修改,又不需要区间查询,拿主席树这种区间数据结构维护不是浪费了吗?再者,非叶子节点里面都不存信息,这不更离谱了吗?那我要告诉你,树形结构起着支撑与平衡的作用。甚至可能可以证明用主席树实现可持久化数组是最优的。
模板:https://www.luogu.com.cn/record/47291192
可持久化并查集
就维护可持久化数组就可以了。路径压缩的复杂度是均摊的,在可持久化中会失效(比如反复访问一个回答询问很慢的历史版本,就 GG 了)。所以只能用启发式合并 / 按秩合并实时保持平衡。
那么就需要维护父亲和子树大小两个数组,可以开两个主席树,当然也可以写到一起节省空间。