核心概述:莫队算法(含树上莫队)通过对查询重排为“近似旅行路径”,在相邻查询间仅增删端点元素以复用状态,实现离线解区间/树路径查询,复杂度约 O(N√Q)。

原文引述:

Description: Answer interval or tree path queries by finding an approximate TSP through the queries, and moving from one query to the next by adding/removing points at the ends. If values are on tree edges, change \texttt{step} to add/remove the edge and remove the initial \texttt{add} call (but keep \texttt{in}). Time: O(N \sqrt Q) Status: stress-tested

展开阐述:

  • 定义与问题背景、适用场景
    • 目标:批量处理区间或树路径查询,通过在查询间“就地移动”窗口/路径,减少每次从零开始的代价。
    • 方法:对查询排序,使相邻查询“距离小”,仅需在两端 add/del 少量元素即可过渡到下一查询。
    • 适用:各类可由端点增删维护的可交换、可逆的统计量(如不同元素个数、频率函数、贡献和等)。
  • 接口职责与外部依赖
    • 需由调用方实现:
      • add(ind, end):在左端(0)/右端(1)加入下标 ind 的元素;
      • del(ind, end):对应删除;
      • calc():在当前窗口/路径状态下返回答案。
  • 数组莫队(mo)的核心流程
    • 分块:设块大小 blk ≈ N/√Q。
    • 排序键:K([L,R)) = (L/blk, R ^ -( (L/blk) & 1 )),即按块编号排序并对 R 采用蛇形顺序,降低回退幅度。
    • 执行:
      • 维护当前窗口 [curL, curR),依排序依次移动到目标 [L,R):
        • while (curL > L) add(—curL, 0); while (curR < R) add(curR++, 1);
        • while (curL < L) del(curL++, 0); while (curR > R) del(—curR, 1);
      • 调用 calc() 记录答案。
  • 树上莫队(moTree)
    • 预处理:DFS 得到 I、L、R、par、in 等数组,以支持排序与祖先关系判定。
    • 排序键:K([a,b]) = (I[a]/blk, I[b] ^ -( (I[a]/blk) & 1 ))。
    • 路径迁移:
      • 使用 step 宏在游走时对当前节点 c 进行“切换”(in[c] 取反,配合 add/del 与 end),两端逐步收敛至目标端点;
      • 若权值在边上:依据原注释,将 step 改为对边 (a, c) 的增删,并移除初始 add(保留 in 标记)。
    • 记录:通常在 end==1 时写入当前答案。
  • 复杂度与边界条件
    • 理论/经验复杂度约 O(N√Q) 或 O((N+Q)√Q);树上版本同阶。
    • add/del 必须可交换和可逆;否则在来回移动时答案无法一致维护。
    • 选择合适 blk,可有效减少指针震荡;蛇形优化针对 R 指针的往返。
  • 实现细节与坑
    • 区间端点约定为半开 [L,R);若使用闭区间需在迁移与 calc 中统一处理。
    • 树上 in[] 与 step 一致性:保证每次切换不会重复计入或漏计。
    • 边权版本的改动:严格按注释调整 step 与初始化流程。
  • 变体/扩展
  • 正确性要点
    • 通过排序将查询“近邻化”,再依靠 add/del 的可逆性和交换性保证不同访问顺序下状态一致,确保 calc 的正确输出。

关联节点