“离线动态连通预先知道每条边的活跃时间,可用时间线段树和 rollback DSU;HDT 不知道未来删除时刻,付出更复杂的分层 replacement 搜索。把离线总时间除以操作数不能得到在…”
形式陈述 ​
从操作流生成活跃区间 ​
目标是在无向图的 add、remove、query 操作序列上回答连通查询,并且全部 (min(u,v), max(u,v)) 作为键,并让栈区分同端点重边。
add 把当前时刻压栈,remove 弹出匹配的 add 时刻并产生半开活跃区间
把每个活跃区间分解为时间线段树的
DFS 与回滚不变量 ​
深搜时间树时,进入节点前记录可回滚并查集快照,再把该节点的所有边 union。到达代表时刻
若产生
另加线性扫描和区间构建成本。最后一个
直觉
删除之所以难,是因为普通并查集只会合并,不能把一条旧边从当前状态抽走。离线视角把“边何时存在”提升为一条时间区间:时间树把区间拆成若干完整覆盖块,DFS 进入块时加入边、离开块时撤销。于是数据结构始终只做擅长的合并与栈顶回滚,却能在每个叶子重现那个时刻的整张活跃图。
分治和线段树是同一时间递归的两种写法。显式线段树先保存规范节点;递归写法在区间中点处分配覆盖整个子问题的边,再把其余区间下放两个孩子。两者共享“根叶路径恰含当前时刻所有活跃边”的不变量。
例子与边界
重边与引用计数 ​
同一端点对可能连续添加两次,再只删除一次。若把端点对当作布尔状态,第一次删除就会错误地让边完全失活。可以按边 ID 分别配对,也可以维护端点对引用计数:计数从
采用栈配对时,remove 应弹出最近一次未匹配 add。若操作语义指定特定边 ID,就必须按该 ID 删除,不能用任意 LIFO 配对代替。删除不存在的边、扫描结束仍有未配对 add,以及闭区间/半开区间混用,都应在预处理阶段明确处理。
模型边界 ​
算法依赖预先知道未来删除时刻,是 offline 方法,不是在线 fully dynamic connectivity。半开区间
推论与应用
预处理保存每个边身份的 add 栈、
离线动态连通常作为“时间分治 + 可撤销状态”的标杆:同一结构还能处理区间生效约束、批量版本验证和某些离线二分图查询。若更新必须到来即答,或需要最坏/摊还多对数更新时间,则要转向 Euler-tour tree、link-cut tree 或分层动态森林等在线结构;这些算法不能从本页的预知未来假设直接推出。
参考资料
- David Eppstein, Zvi Galil, Giuseppe F. Italiano, and Amnon Nissenzweig, “Sparsification—A Technique for Speeding Up Dynamic Graph Algorithms,” Journal of the ACM 44(5), 1997, pp. 669–696.
- Erik D. Demaine, Advanced Data Structures, MIT 6.851, Spring 2012, lecture notes on dynamic graphs, persistence, and rollback.