继续回来写博客……记录点有意思的题目什么的。
貌似写过这个的没多少人……所以我也记录一点。
首先序列上的莫队大家都应该很熟悉了……
那么树上的莫队要怎么搞呢?
先来看个题目……SPOJ COT2:求树上两点间路径上有多少个不同的点权。
序列上的莫队是把询问按照左端点分块了……可是树上没有左端点,怎么办呢?我们把树分块。
按照DFS时间戳顺序,将树分成O(sqrt(n))个大小为O(sqrt(n))的块,那么树上的莫队询问排序的第一关键字就是第一个节点所在的块了!
这样分块以后,任意两个块之间的距离也是O(sqrt(n))级别的,所以时间复杂度是有保证的。
第二个关键字自然就是节点的DFS时间戳了!
但是,还有一个问题。树上的区间要怎么转移呢?要怎么从一个区间变到另一个区间呢?
这就有些难了,因为树上有LCA,貌似不好处理。
Orz了wyfcyx后,找到了vfk的博客看了一下。
“
用S(v, u)代表 v到u的路径上的结点的集合。
用root来代表根结点,用lca(v, u)来代表v、u的最近公共祖先。
那么
S(v, u) = S(root, v) xor S(root, u) xor lca(v, u)
其中xor是集合的对称差。
简单来说就是
节点出现两次消掉。
lca很讨厌,于是再定义
T(v, u) = S(root, v) xor S(root, u)
观察将curV移动到targetV前后T(curV, curU)变化:
T(curV, curU) = S(root, curV) xor S(root, curU)
T(targetV, curU) = S(root, targetV) xor S(root, curU)
取对称差:
T(curV, curU) xor
T(targetV, curU)
= (S(root, curV) xor S(root, curU)) xor (
S(root, targetV) xor S(root, curU))
由于对称差的交换律、结合律:
T(curV, curU) xor
T(targetV, curU)
= S(root, curV) xor
S(root, targetV)
两边同时xor
T(curV, curU):
T(targetV, curU)
=
T(curV, curU) xor
S(root, curV) xor