题解:P5416 [CTSC2016] 时空旅行

题意

\(n\) 个点集 \(S_{0\sim n-1}\)。初始时 \(S_0\) 只包含一个 \(id=0\) 的点 \((0,c_0)\)。对于每个 \(S_i\),其由 \(S_{fr_i}\) 得来,然后有两种可能:

  1. 给定 \(id,x,c\),表示向 \(S_i\) 中加入一个编号为 \(id\) 的新点 \((x,c)\)
  2. 给定 \(id\),表示删除 \(S_i\) 中编号为 \(id\) 的点。

\(m\) 次询问 \(p,x_0\),你需要求出 \(\min\limits_{(x,c)\in S_p}\left\{(x-x_0)^2+c\right\}\)\(1\leq n,m\leq 5\times 10^5\)\(|x|,|x_0|\leq 10^6\)\(0\leq c\leq 10^{12}\)

题解

击杀了,感觉不到黑。

套路地建出版本树,对于一个点 \(u\),对应的点集 \(S_u\),若其对应操作为加入一个新点 \(id\),则相当于给整个子树内的点集都加入 \(id\),否则则相当于给整个子树内的点集都删除 \(id\)。放到 DFS 序上考虑,显然所有点的出现区间会在 DFS 序上形成最多 \(n\) 个连续区间,DFS 的时候简单维护即可找出。

拆一下询问的式子,变成 \(x_0^2+\min\limits_{(x,c)\in S_p}\{-2x\cdot x_0+(x^2+c)\}\)。显然可以把每个点视作一条 \(k=-2x,b=x^2+c\) 的直线,对点集内的直线建出上凸壳即可查询出 \(\min\)

现在我们有 \(\mathcal{O}(n)\) 个区间 \(l,r,id\),表示编号为 \(id\) 的点会在 DFS 序上 \([l,r]\) 对应的点集里出现。考虑线段树,在每个节点上维护一个 vector,每个区间会在线段树上分成 \(\mathcal{O}(\log{n})\) 个节点,把 \(id\) 插进这些节点对应的 vector 里。然后对于线段树的每个节点,把这个节点的 vector 对应的直线排序后单调栈建出上凸壳,查询时对每个经过的节点都二分一下。这样复杂度是 \(\mathcal{O}((n+m)\log^2{n})\) 的。

显然可以优化。我们提前把 \(\mathcal{O}(n)\) 个区间按照对应直线的斜率排序,这样所有插入操作完成后,每个 vector 里的对应直线就已经排好序了。询问可以同理按照 \(x_0\) 排序,把二分改成暴力走指针。这样两边复杂度都降至 \(\mathcal{O}(n\log{n})\) 了。

注意细节,相同斜率的直线只需保留截距最小的那个。

posted @ 2025-12-06 11:54  P2441M  阅读(14)  评论(0)    收藏  举报