虚树学习笔记

全机房的小伙伴们都早就会虚树了,就我不会,于是决定学习一下虚树。前两天看了一些别人的讲解,大体明白了虚树的思想,于是写一篇学习笔记。

虚树经常用来解决在一棵树上选出若干点,有若干次询问,每次询问求这若干点的某一个东西,一般选出的点的总数是1e5量级的。这类题的一个暴力做法通常是可以对于每次询问都暴力树形dp,但是这样复杂度就比较高,我们发现每次只选出了一些点,但是却对整棵树重新做了一遍dp,看起来很浪费,我们想要用尽可能少的点数构成一棵新的树,要求新的树能包含这次询问需要的所有信息,并且这棵树的点数尽可能少,这样我们只需要在这棵新的树上dp就能求出这次询问的答案了。我们把这棵新树叫做虚树。下面我们来讲一下对于一次询问,如何建出一棵对应的虚树。

首先我们对原树dfs,预处理出一个倍增LCA的父节点数组、深度和每个点的dfs序。然后对于每次询问,我们把所有点按照dfs序排序。我们一般选一个不会被选到的点作为虚树的根,如果都可能被选到,我的一个做法是选一号点为根,并且在询问时特判一下是否选中了一号点。update:还yy了一种写法,就是先求所有点的LCA,然后选这个点当根,显然这个点肯定在虚树里,并且可以看作是虚树的根。

我们构建虚树的方法是这样的:首先先把你选的根确定,我一般都是用1号节点,然后我们用一个栈来维护已经用到的一些点,栈中的点要满足是根到某个点形成的一条链上的点。当栈中的元素大于等于两个的时候,我们开始判断要对栈进行什么操作。我们按照dfs序插入所有当前询问选中的点。首先,我们求出当前要插入的点与栈顶元素的lca,接下来分类讨论。如果这个lca就是栈顶元素,那么意味着要插入的这个点是栈顶元素子树内的一个节点,他们相互连接之后仍然是一条链。那么根据题目需要,有时候我们需要插入当前点,有的时候可能在虚树上只需要保留lca。然后对栈顶元素不是两者的lca的情况进行讨论。如果栈顶的第二个元素的的dfs序大于等于lca的dfs序,就意味着当前点和栈顶元素不在栈顶第二个元素的同一棵子树内,那么我们就把栈顶的两个元素连边,然后删除当前栈顶,直到不满足上述条件。另外需要特判一下删完之后当前栈顶是否是lca,如果是的话就不用管,如果不是的话就把栈顶与lca连边,然后把原栈顶元素出栈,把lca入栈。在进行完上述操作后将当前要插入的点入站即可。最后如果栈不是空的,那么我们需要不断地把栈顶第一个元素和栈顶第二个元素连边,直到把栈弹空。

使用虚树的话要注意经常需要用到vector来存新树的边,否则的话你每次询问清空原来的连边信息时会复杂度退化。

学习笔记就讲到这里,例题如果需要的话请到博客里找吧。博主比较懒,就不挂链接了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值