LCT.
先考虑插入操作,经过观察容易发现,一个点被插入后,要么成为它前驱的右儿子,要么成为它后继的左儿子.
且这两个位置中恰有一个位置是空的,所以插入时在 set 中询问一下前驱后继即可.
考虑旋转操作,经过观察容易发现,如果把最小值转到根,就是先把它的右子树接在它的父亲上,再让它成为根的父亲.
旋转最大值也差不多,把它的左子树接在它的父亲上,再让它成为根的父亲.
如果接下来要将它删除,就不用从根向它连边.
而其他部分的形态是不变的,于是每次操作只会连/断 $O(1)$ 条边,可以用 LCT 来实现这些操作.
即,用一棵 LCT 维护这棵树的形态,另开数组记录每个节点在原树中的左右儿子以及父亲,并记录原树当前的根.
每次要询问一个点的深度时,就在 LCT 上询问它与根的距离即可.
可以先将所有权值离散化,然后将每个节点的权值当做它的标号.
时间复杂度 $O(m\log m)$ .
1 | //%std |