前言
树上莫队的核心思想,就是将一棵树转化成一个序列,然后用普通莫队来搞。
初始化
以一棵树为例:
要想对这棵树进行树上莫队,我们第一步就是用一个(s)数组把它的括号序存下来:
(id) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
(s) | 1 | 2 | 4 | 7 | 8 | 8 | 7 | 4 | 5 | 5 | 2 | 3 | 6 | 6 | 3 | 1 |
同时,我们用(I)数组存储每个数字在括号序列中第一次出现的位置,用(O)数组存储每个数字在括号序列中第二次出现的位置。
处理查询
首先,对于询问的两个数(x,y),我们要保证(I_xle I_y)(这可以通过(swap)进行保证)。
对于查询的两个节点,我们需要对其进行分类讨论。
对于祖先关系的两个点(以(1,5)为例)
我们需要分别找到(x,y)在括号序列中第一次出现的位置(即(1)和(9))。
然后就能得到一段区间:
[1,2,4,7,8,8,7,4,5
]
对于出现两次的元素,我们将它去掉(在程序中只要判断一个元素出现次数的奇偶性即可)。
然后就得到这样一个区间:
[1,2,5
]
而这些恰好就是我们要求解的元素。
简单说,就是求解区间([I_x,I_y])即可。
对于非祖先关系的两个点(以(5,6)为例)
我们需要找出(x)在括号序列中第二次出现的位置和(y)在括号序列中第一次出现的位置(即(10)和(13))。
然后就能得到这样一个区间:
[5,2,3,6
]
注意,对于出现两次的元素,我们同样需要将它去掉,只不过这个例子中刚好没有出现这样的情况而已。
然后我们可以发现,这个区间中的元素就是除(LCA_{x,y})以外要求解的全部元素。
则我们单独计算(LCA_{x,y})的贡献,保存答案后再将其贡献减去即可。
例题
好好想一下,就可以发现树上莫队其实挺好理解的。
下面是一道例题:【BZOJ3757】苹果树。