“深搜时间树时,在进入节点时把该节点所有边 union 到可回滚 DSU。不变量是:到达代表时刻 $t$ 的叶时,DSU 恰含所有覆盖根到叶路径的边,也就是 $t$ 时活跃图。叶上用 Find…”
状态与接口 ​
使用 union by size/rank,不做路径压缩。Find 沿父指针到根,树高
不变量与复杂度 ​
每条历史记录恰好描述一次可逆原子修改,按逆序恢复后,父森林、size 和附加摘要都回到快照状态。Union、Find 最坏
递归搜索例子 ​
在分治递归节点加入一批当前区间有效的边,进入孩子前保存栈长;孩子处理完 rollback 到该长度。左右孩子因此共享父节点状态,却不会互相泄漏修改。这比复制整个 DSU 状态节省空间和时间。
易错边界 ​
重复 union 两个已连通顶点不改变结构,但快照语义必须一致:可压一个 no-op 标记,或只以栈长度回滚并确保调用方不按 union 次数撤销。路径压缩会修改整条路径,若不逐项记录就无法恢复。rollback 只能撤销栈顶历史;任意版本查询属于持久化,任意过去编辑属于追溯结构。
可回滚摘要 ​
若每个分量还维护权重和、二分图 parity 或最小编号,union 时必须把所有被覆盖字段的旧值一并压栈。恢复顺序与写入相反,且只把小根挂到大根,保证 Find 最坏
历史栈空间与成功合并次数及附加字段数线性。深度优先分治中最大同时栈长通常为当前根叶路径所加入边数,而非所有递归节点边副本之和。
栈中究竟记录什么 ​
执行 union(a,b) 前先找两根 (被挂根, 旧父亲, 新根, 旧大小) 推栈。恢复时按相反顺序写回,不能重新调用 union 猜测旧状态。
一次递归搜索的状态轨迹是:
snap = history.length;- 应用当前节点代表的所有边;
- 递归访问子问题并回答叶查询;
rollback(snap),逐项弹栈到原长度。
按大小合并使 find 最坏
参考资料
- James Driscoll et al., Making Data Structures Persistent, JCSS, 1989.
- Erik Demaine, MIT 6.851 Dynamic Graphs Notes, rollback union-find.