P11191 「KDOI-10」超级演出 解题报告


P11191 「KDOI-10」超级演出 解题报告

1. 题目解读与分析

首先,我们来深入理解题目的核心规则。这是一个在有向无环图(DAG)上进行的游戏。

  • 场景: 一个包含 \(n\) 个点 \(m\) 条边的有向无环图。节点1是唯一的终点(舞台),其余节点(\(2, \dots, n\))是候场室,每个候场室初始都有一个剧团。
  • 行动: 按给定的命令序列 \(a_1, \dots, a_k\) 对候场室发布出场命令。
  • 出场条件: 对候场室 \(u\) 的命令有效,必须满足两个条件:
    1. \(u\) 的剧团还在候场室(未出场)。
    2. 存在一条从 \(u\) 到舞台 \(1\) 的路径,这条路径上所有中间的候场室都已空(即它们的剧团都已成功出场)。
  • 目标: 对于 \(q\) 次独立的询问,每次给出一个区间 \([l, r]\),我们需要计算如果只执行 \(a_l, \dots, a_r\) 这一系列命令,最终会有多少剧团留在候场室。

由于每次询问都是独立的,且数据规模很大,为每次询问都进行暴力模拟是不可行的。我们必须找到一个更高效的预处理和查询方法。

2. 核心思路:将问题转化为依赖关系

问题的关键在于“出场”这个行为的依赖性。一个剧团 \(u\) 能否出场,取决于它下游某个或某些剧团是否已经出场。我们可以将这个依赖关系量化。

我们换一个角度思考:对于第 \(i\) 个命令 \(a_i\)(在 \(1, \dots, k\) 的完整序列中),它要成功执行,需要满足什么样的前提?

这个前提是,它所依赖的路径上的所有剧团,都必须收到过成功的出场命令,并且这些命令的时间点都必须在 \(i\) 之前。为了让条件最容易满足,它会选择那条“前提最不苛刻”的路径。

我们可以为每个命令 \(a_i\) 预计算一个“前提值”,记作 \(w_i\)

\(w_i\) 的定义:要让第 \(i\) 个命令 \(a_i\) 在某个询问区间 [l, r] 中成功,这个区间的起始点 l 必须满足 l <= w_i。换句话说,\(w_i\) 是保证 \(a_i\) 能够成功执行所需要的最晚的那个前置命令的起始时刻。

如果对于一个询问 \([l, r]\),我们想知道命令 \(a_i\)(其中 \(l \le i \le r\))是否有效,只需要检查它的前提条件是否被满足,即 \(l \le w_i\)

只要我们能预计算出所有 \(w_i\),问题就变得清晰多了。

3. 如何计算前提值 \(w_i\)

我们按顺序(\(i\) 从 1 到 \(k\))来计算每个 \(w_i\)

  • 基础情况:如果候场室 \(a_i\) 能直接到达舞台 1(即存在边 \(a_i \to 1\)),它不依赖任何其他剧团。它的成功只取决于它自己被命令。因此,它的前提就是它自己,我们定义 \(w_i = i\)

  • 递推情况:如果 \(a_i\) 不能直接到舞台 1,它必须经过某个下游的候场室 \(v\)。为了让 \(a_i\) 能出场,它需要至少一条通往舞台的路径是通畅的。假设它选择经过 \(v\),而 \(v\)\(i\) 之前最后一次被成功命令的前提是 \(w_j\),那么 \(a_i\) 的成功就间接依赖于 \(w_j\)

    由于 \(a_i\) 可以选择任意一条通畅的路径,它会选择那个“前提条件最容易满足”的路径。“容易满足”意味着对起始点 \(l\) 的约束最宽松,即 \(l \le W\) 中的 \(W\) 尽可能小。但这里是“或”的关系,比如可以走依赖前提 \(W_1\) 的路,或者走依赖前提 \(W_2\) 的路,只要满足 \(l \le W_1\)\(l \le W_2\) 即可,这等价于 \(l \le \max(W_1, W_2)\)。因此,我们需要取所有下游路径中,那个最苛刻的前提。

    我们可以得到 \(w_i\) 的计算公式:
    \(w_i = \max_{v \in \text{后继}(a_i)} \{ w_j \}\),其中 \(j\) 是在 \(i\) 之前对 \(v\) 的最后一次命令的索引。

    为了方便计算,我们用一个数组 rev[u] 来记录节点 u 最后一次被命令时计算出的 \(w\) 值。公式简化为:
    w[i] = max(rev[v]),其中 va[i] 的所有直接后继。

加速计算:根号分治
直接按上述方法计算,若某个节点度数很大,复杂度会很高。这里可以使用根号分治优化:

  1. 设定阈值 \(B\)(如 \(\sqrt{m}\))。
  2. 小度节点 (度数 < B):后继少,直接遍历后继,使用 rev 数组计算 \(w_i\)
  3. 大度节点 (度数 ≥ B):后继多,反向更新。我们为每个大度节点 \(p\) 维护一个值 tw[p],记录其所有后继中最大的 rev 值。每当计算完一个 \(w_i\) (针对节点 \(a_i\)),我们就去更新 \(a_i\) 的所有大度前驱tw 值。当需要计算一个大度节点自身的 \(w\) 值时,直接取 tw 即可。

4. 解答询问:二维数点问题的转化与求解

预处理完所有 \(w_i\) 后,对于每个询问 \([l, r]\),问题转化为:

统计在 \(a_l, \dots, a_r\) 中,有多少个不同的候场室 \(u\),满足存在某个 \(i \in [l, r]\) 使得 \(a_i=u\)\(w_i \ge l\)

这是一个典型的二维数点问题,可以用离线处理 + 树状数组(BIT) 高效解决。

4.1 转化为二维平面上的点

我们可以将每个命令 \(a_i\) 想象成一个二维平面上的点 \(P_i(i, w_i)\)

  • x 轴 代表命令的时间 i
  • y 轴 代表命令的前提值 w_i

一个询问 [l, r] 就是要统计满足下面条件的点的种类数(不同候场室):

  1. \(l \le i \le r\) (点的 x 坐标在查询区间内)
  2. \(l \le w_i\) (点的 y 坐标满足前提)

这个问题的难点在于如何处理“种类数”,即对同一个候场室的多个满足条件的点只计数一次。

4.2 离线扫描线 + 树状数组

这正是“离线扫描线”算法的用武之地。

  1. 离线处理:将所有 \(q\) 个询问存储起来,不立即回答。将它们按右端点 r 从小到大排序
  2. 扫描与处理:我们从 \(i=1\)\(k\) 遍历命令序列,可以想象一条竖直的“扫描线”从左向右移动。当扫描线移动到位置 i 时,我们处理第 i 个命令,并回答所有右端点 \(r=i\) 的询问。
  3. 树状数组维护“活跃点”:为了处理“种类数”的限制,我们只关心每个候场室最后一次被命令的信息。我们用树状数组来维护这些“活跃点”的 w 值分布。
    • 更新:当扫描线处理到第 \(i\) 个命令 a[i] 时,其对应的点是 (i, w[i])
      • 如果候场室 a[i] 之前出现过(假设其上一个活跃点的 w 值为 old_w),说明旧的活跃点 (j, old_w)\(j<i\))已过时。我们在树状数组的 old_w 位置减 1,移除它的贡献。
      • 然后,我们将新的活跃点 (i, w[i]) 加入。在树状数组的 w[i] 位置加 1。
      • 我们用一个 lst[u] 数组记录每个候场室 u 当前活跃点的 w 值。
    • 查询:当扫描线移动到 \(r\) 时,我们回答所有右端点为 \(r\) 的询问 \((l, r)\)
      • 此时,树状数组里存储了所有在 \(1 \dots r\) 时间内出现的候场室的、最新的 w 值信息。
      • 我们要查询的是,这些活跃点中有多少个满足 w >= l
      • 这在树状数组上是一个范围查询:总活跃点数 - w值小于l的点数
      • 具体公式为:ask(k) - ask(l-1)(其中 ask(x) 查询 w <= x 的点的数量,kw的最大可能值)。
      • 这个结果就是成功出场的剧团数量。
      • 最终答案为:总剧团数 \((n-1)\) - 成功出场数。

5. 算法流程总结

  1. 预处理 w 数组

    • 遍历图,根据度数将节点分为大度和小度。
    • \(i=1\)\(k\) 遍历命令序列 \(a\)
    • 使用根号分治策略,结合 rev (记录节点最新w值) 和 tw (为大度节点服务) 数组,计算出每个 \(w_i\)
  2. 回答询问

    • 将所有询问按右端点 \(r\) 排序。
    • 初始化一个树状数组和记录节点最新 w 值的 lst 数组。
    • \(i=1\)\(k\) 进行扫描:
      a. 处理命令 a[i]:更新树状数组,将 a[i] 的旧贡献(如果存在)移除,加入 w[i] 的新贡献,并更新 lst[a[i]]
      b. 处理所有右端点 \(r=i\) 的询问 (l, i):利用树状数组计算出场剧团数,公式为 当前总贡献数 - ask(l-1)
      c. 计算剩余剧团数 (n-1) - 出场数,并存储答案。
    • 按原始顺序输出所有答案。

该算法通过巧妙的预处理和问题转化,将复杂的模拟过程变成了一个高效的、可离线处理的二维数点问题,最终通过树状数组在优秀的复杂度内解决了问题。

posted @ 2025-07-16 11:03  surprise_ying  阅读(20)  评论(0)    收藏  举报