IOI 2020 网络站点 题解

First Post:

Last Update:

非常好的一道题,其实已经想到了正解思想,但被“标号可能重复” 的弱智问题卡住了,没有意识到直接按那个过程做 dfs 即可。

首先考虑编号最大值为平方怎么做,对每个点算出其 然后压倒标号里面,回答询问时提取出这些信息就能判断出 在不在某个 的子树内了。

然后发现有很多 的记录是完全没有必要的。设 长度为 (此时我们已经从 中把 的父亲删去),且假设其按照原树的 dfs 序排列,那么对于 的差正好就是 对应节点的

那只记录 够不够呢?大部分情况下是够的,对于 小于最后一个儿子的 的情况,我们都能正确回答询问。但问题在于,我们不知道最后一个子树在 dfs 序上的终止位置。

我们知道 本质是每个节点入栈的顺序,那出栈的顺序行不行呢?其实有相似的问题,我们不知道第一个子树在出栈序上的左边界。

考虑问题的本质,设 共有 个邻居,我们的目标无非是将 按照原来的树结构划分成 段(其中 相邻),并且通过标号信息快速算出这 段是怎么划的。而在询问的时候,函数给了我们 个信息,即父亲,自己和所有儿子的标号。父亲的标号很难有什么作用,那我们就要把自己和所有儿子的标号全都用上,才能把 区分成至少 个部分。

那为什么之前的 标号只能找到 段呢?本质上是因为对于 的第一个儿子,其 永远等于 ,我们相当于浪费了一个信息。

那考虑把奇数层用入栈序,偶数层用出栈序。注意这里的出入栈序并不指代某个具体的顺序,而是说对于奇数层的节点,其标号为子树中所有标号的最小值,对于偶数层的节点,其标号为子树中所有标号的最大值。 用一个 dfs 即可实现这个过程。这么标完之后,判断 在奇数层还是偶数层其实也是简单的。如果 小于 中的最小值,那在 处显然是先加入的 ,再加入儿子。那么 中最大值就是 的父亲,除开这个值以外的 则是每个子树标号的右边界。此时回答询问就很简单了。反之, 一定大于 中的最大值,也可以同理回答询问。