QOJ10007 Holes in Queue

题意简述

有一个无限长的序列,初始第 \(i\) 个数为 \(i\)。执行 \(d\) 次删除操作,每次同时将第 \(a_i(\forall 1\le i\le n)\) 个数删除。

接下来有 \(q\) 次查询,每次询问删除 \(d\) 次后第 \(x\) 个数是什么。

\(1\le n,q\le 5\times 10^5\)\(1\le a_i,d,x\le 10^{12}\)

题解

首先将 \(a\) 从小到大排序,考虑记 \(f(x)=f_{(1)}(x)\) 表示删一次以后,位置 \(x\) 会变成什么数,显然 \(f_{(k)}(x)=f_{(k-1)}(f(x))\),则 \(f_{(d)}(x)\) 即为查询的答案。

考虑对于每一个数 \(x\),连一条 \(x\rightarrow f(x)\) 的边,表示一次操作会从 \(x\) 跳到 \(f(x)\),则 \(f_{(d)}(x)\) 即为从 \(x\)\(d\) 次后跳到的点。

例如当 \(a=(2,6,9,12)\) 时如下:

3409470-20250907221115589-1704999781

接下来最关键的,是将所有数分块,使得每个块内的点只向下一个块内的点连边。

显然若查询的数 \(x<a_1\),则答案就是 \(x\)。于是我们只需要考虑 \(\ge a_1\) 的数。

\((a_1)\) 单独分一个块,假设将所有 \(a_i\) 位置的点打上标记,则接下来每个块只需满足不被标记的点的个数恰好等于上一个块内的总点数

容易发现每个块的长度 \(\le n\),且最后会有无限个长度为 \(n\) 的块。

观察相同长度的块,发现其中只有第一个块内有被标记的点。除了最后一个块,每个块内的点都向下一个块内对应的点连边。

容易快速处理出每种长度的块开始的位置。当块的长度增加时,前一个块的第 \(i\) 个点向下一个块的第 \(i\) 个未标记的点连边。

于是可以将每个位置与 \(a_1,a_2\dots,a_n\) 中的一个数对应。从小到大枚举块的长度,维护一个序列,每次将前一个序列中的数对应到这个块的空位上,中间插入那些新的 \(a_i\)。这部分容易用线段树/平衡树处理。

然后再考虑处理查询。我们找到 \(x\) 所在的块和在块内的位置,若其所在的块为 \(b\),则答案的块就是 \(b+d\)。考虑离线。当处理到 \(b\) 的块长时,找到其对应的 \(a_i\),处理到 \(b+d\) 的块长时再找到这个 \(a_i\) 新的位置,最后再对应到第 \(b+d\) 个块中的位置就做完了。

时间复杂度 \(\mathcal O((n+q)\log n)\)

posted @ 2025-10-17 15:37  zifanwang  阅读(7)  评论(0)    收藏  举报