P3233 [HNOI2014]世界树
每次给出mi个点,查询每个点控制的点的个数,每个点由离他最近编号最小的点控制。
首先按照套路建出虚树,注意特判1节点,然后用栈维护右链,然后不断弹栈建边。
然后进行dp,求解出虚树上每个点的最近控制点,对于控制点就是自己,需要两边dfs,第一遍处理子树,第二遍从上到下dp,这样就处理出在整个树上的控制点。
然后对于其他点我们需要分类讨论:
第一类就是直接连接到虚树节点上,但是不包含虚树节点的子树,这些点必然由g[u]控制,具体计算size可以用siz[u]减去包含虚树节点的siz。
第二类就是在虚树节点之间的节点,这一部分是一个链上挂了许多子树,并且其中没有虚树节点,这一部分要么由g[u]控制,要么由g[v]控制。然后中间必然有一个分割点,我们可以考虑倍增求解这个点的位置。
然后计算答案还需要知道v所对应子树是u的哪一个儿子,这个也可以通过倍增求解,然后就可以用这些点来计算对应这一部分的贡献了。
注意这里的虚树节点可能是lca节点,所以对应贡献必须计算到g[u]和g[v]上。
代码细节:
- 建立虚树的时候一定要小心,每次弹栈都需要建边
- 还有倍增寻找分割点的时候要注意,两端点属于同一个控制点的情况,虽然可以直接处理。