「SHOI2014」三叉神经树(加强版)题解
题意:
给定一棵有 个结点的有根树,其中有 个实点和 个虚点,每个实点有 个儿子而所有虚点都没有儿子。实点从 到 编号,虚点从 到 编号,且 号点为根。
每个点都有一个点权,其中,虚点的点权由输入确定且只可能为 或 ,而实点的点权为三个子结点的点权的众数。你需要支持三种操作(操作总数为 ):
- 操作 :输入 ,表示将虛点 的新点权设为其原点权异或 后的值。
- 操作 :输入 ,表示给定两实点 ,若 不同且不为祖孙关系则将 的父结点与 的父结点交换。
- 操作 :输入 ,表示查询实点 的点权。
题解:
我校大佬LinZhengyu对于原题可以让树剖过非常生气,于是他加强了这道题,把树剖卡掉了 (毒瘤啊)。
考虑使用 实现这些功能 ,想用树剖?你是想要被嬴政弃市吗? 。
操作 :
这是非加强版就有的操作。
首先显然有:每一次修改权值改变的点的集合一定是某一条自上而下的链,并且不一定是从根开始的,但是一定以被修改点结尾的。
我们定义 为 号节点的子节点的点权和。
我们发现:
- 若修改的点是从 变成 ,那么从修改点一直往上,只有 的点的点权会改变(从 变成 )
- 若修改的点是从 变成 ,那么从修改点一直往上,只有 的点的点权会改变(从 变成 )
那么我们修改一个点,要找到的就是深度最大且 的点。
这个可以二分求得,但是这样会多一个 (然后你就被毒瘤出题人卡了),我们考虑直接维护。我们记 为从 号点往上,深度最大且 的点,然后我们只需要在 中魔改即可,具体细节如下:
以维护 为例( 同理):我们先从其中的一个儿子转移上来,比如说 ,如果这时 还是没有值,我们就考虑 点本身,如果符合要求,那么 ,否则 。
这之后就是修改一条链的操作了,直接套模板。
细节方面:
设当前被修改点为 。
- 在修改的时候,不能将被修改的叶子节点也放到 当中(即 的时候一定要从 开始 ),因为如果叶子节点的 为 ,那么这个 里面的 都是这个叶子节点,那么我们维护就没有意义了。
- 在把 旋根之后,一定是修改右子树,而不是修改整个子树,因为左子树的信息并不会改变。
- 在修改了右子树之后,不要忘记对 进行单点修改。
单次操作时间复杂度为 。
操作 :
这是 毒瘤 出题人为了卡树剖而加的操作。
但其实这个操作在我们会了操作 后是没有什么难度的。显然,如果 的点权相等,可以直接用 个 操作解决;如果不相等,那么就是先修改这两个点(与操作 不同的是,这次修改不改变实际点权,只是假装这个点被修改了,以此来影响祖先),然后再换父亲。单次操作时间复杂度为 。
操作 :
这就是一个查询操作,显然直接把 上去,就可以直接查询了,单次操作时间复杂度为 。
综上所述,我们成功用 解决了这道题,时间复杂度为 ,空间复杂度为 ,把树剖吊起来打。
Code:
1 |
|