PrepStack · Markdown HTML

离线排序 + 逐步激活 + 并查集

并查集、MST 与离线激活 · HTML

数学 / 逻辑形态

边或点带 key;查询只依赖 key 与阈值 t 的比较。排序事件与查询,使可用集合单向增长。

识别信号

容易误判的相似信号

SignalWhy it is different
必须实时按到达顺序回答离线排序改变处理次序,真正在线问题需其他结构。
状态既加入又删除普通 DSU 适合单向激活;非单调变化需 rollback 或分治结构。

核心不变量

回答阈值 t 前,恰好所有满足条件的事件已激活,DSU 组件等于该阈值下真实连通块。

状态、转移与处理顺序

ItemDefinition
State排序事件、带原下标查询、DSU、扫描指针,以及点模型中的 active 标志。
Transition阈值前进时激活所有新事件并 union;随后读取查询并按原下标回填。
Frontier / order扫描指针左侧全部激活,右侧全部未激活,指针只向右。

Python 骨架

def offline_connectivity(n, edges, queries):
    p = list(range(n))
    def find(x):
        while x != p[x]:
            p[x] = p[p[x]]; x = p[x]
        return x
    def union(a, b):
        a, b = find(a), find(b)
        if a != b: p[b] = a
    edges = sorted(edges)  # (weight,u,v)
    order = sorted((lim, i, u, v) for i, (lim,u,v) in enumerate(queries))
    ans, j = [False] * len(queries), 0
    for lim, i, u, v in order:
        while j < len(edges) and edges[j][0] <= lim:
            _, a, b = edges[j]; union(a, b); j += 1
        ans[i] = find(u) == find(v)
    return ans

正确性思路

  1. 排序保证扫描到 lim 时,所有且仅有 key<=lim 的事件位于指针左侧。
  2. 每个激活边执行 union,所以 DSU 与激活子图组件一致。
  3. 查询只读取当前状态,得到原阈值定义下的连通性。
  4. 按原下标回填使重排不改变输出顺序。

复杂度

TimeSpaceParameters
O((E+Q) log(E+Q)+(E+Q)α(V))O(V+E+Q)V 对象数,E 事件数,Q 查询数

边界条件

错误模式

PatternWhy it fails / fix
同值 tie-breaking 写反<= 条件下同值事件必须先于查询。
按排序顺序 append必须按原查询下标回填答案。
每个查询重建 DSU会失去共享扫描的复杂度优势。

选择与排除规则

相关模板

RelationTemplateBoundary
动态摘要并查集动态连通性激活后维护组件

原创微型例子

环节内容
Result阈值 4 只含第一边;阈值 5 先加入两条同值边再查询。
Scenario边在阈值 2、5、5 激活,查询阈值 4 与 5 的连通性。
Walkthrough指针只右移,每条边只处理一次,两个查询共享此前工作。

Recall prompts

我的补充