bzoj3757: 苹果树

传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3757

思路:像这种链剖 or lct没法做的就是树上莫队了...

不是树上的莫队就是按询问的左端点所在的块为第一关键字,右端点为第二关键字。

但是树上的就不同了,树上不是区间。

于是我们就进行树分块——见bzoj1086

注意这个分块是不需要保证每块的点都联通的,这个分块只要使莫队算法的复杂度有保证就可以了。

也就是块数是O(sqrt(n))的,块的大小是O(sqrt(n))的,块内两点的距离是O(sqrt(n)),相邻两块的距离是O(sqrt(n))的

这样莫队的暴力移复杂度才有保证

于是我们就可以以第一个节点所在块为第一关键字,第二个节点的dfs序为第二关键字对询问排序

然后我们考虑怎么由询问(curU,curV)得到询问(targetU,targetV)的答案

以下来自神犇vfk的博客(看的我整个人都不好了)

http://vfleaking.blog.163.com/blog/static/174807634201311011201627/

用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 S(root, targetV)
发现最后两项很爽……哇哈哈
T(targetV, curU)= T(curV, curU) xor T(curV, targetV)
(有公式恐惧症的不要走啊 T_T)

也就是说,更新的时候,xor T(curV, targetV)就行了。
即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。

还是画图吧,假设有这样的一棵树和两组询问(画的好像有点丑...)


现在的答案是黄点的答案



而我们要求的是这些蓝点的答案


考虑怎么从黄点变成蓝点?

就是XOR上S(curV,root) xor S(curV,targetV),也就是对curV到targetV的路径上的点(除了lca)的存在性取反。

这样我们就可以先把LCA扔出去,算剩下部分的答案,再加上lca的贡献,然后就没有然后了。。。



posted @ 2015-08-10 09:12  orzpps  阅读(241)  评论(0编辑  收藏  举报