题目
分析
首先直接做好像并不好做,树剖什么的好像没什么用。
但是可以观察到我们可以把询问拆成两段,一段是 (u o x) 另一段是 (lca o v) 。(其中 (x) 是 (lca) 的 (u) 方向儿子)
那么我们可以考虑怎么处理前面这一段。
我们可以倍增,预处理出当前点到 (x) 处时最远的颜色。
怎么做呢?我们可以进行一次 (dfs) ,然后直接倍增维护当前点可以到达的后继点,并一边维护当前点到根节点路径上最近的可以成为起始点的祖先。
(到底是怎么样的呢?就是如果我们遇到了一个节点是起始颜色,那么直接在进去的时候暂存这时候的起始点,并把起始点更新为当前点,这样做的话就保证了这个祖先是最近的。)
同时,如果现在祖先上有当前点的后继颜色,那么就更新倍增数组的 (fa[x][0]) 为这个后继节点,然后倍增。
这样就预处理完毕了。
考虑剩下的那一段,我们可以离线询问,在刚刚处理出的每一个 (lca) 处挂一个询问 ((i,col_i)) ,然后再在 (v) 节点打一个结尾标记 (i) 。
接下来我们用可撤销并查集来维护每一个询问当前匹配到的颜色是什么。
具体来说就是在把当前的并查集 (A_{col_x}) 和 (A_{suf_{col_x}}) 合并起来,然后每次到了一个节点查看现在会终止的所有编号目前所在集合,然后答案就是所在集合颜色。
然后在退出子树的时候撤回操作即可。
正确性很显然,但是这样的思路十分巧妙,有待总结。
时间复杂度 (O(nlogn)) 。
代码
待补。