虚树

虚树

在解决树上的问题时,我们经常会查询点对之间的关系。如果直接在原树上进行询问,那么时间级别就会是o(n)级别的,但实际上原树上有许多不必要的点。如果将必要的点挑出来建立一颗新的树,在新树上查询的复杂度就基本为o(1)的了。我们把这样的树叫做虚树,它将两个点之间的链缩减为一条边,极大优化了时间。

那么如何构造呢?

我们预处理出节点的dfs序,令dfn表示dfs序,并将要处理的点以dfs序排序,并开一个栈维护右链

维护右链指的是栈中存下虚树最右的一条链,这样可以保证虚树上的边就代表原树上的链。

维护右链

记栈顶为lit,当前遍历到的点为x。令 f=(lca(lit,x))

  1. f=lit 则直接将x压入栈中。

    这里有一显然的结论:f不可能是x

    因为如果f是x,说明 dfn(f)=dfn(x)<dfn(lit) ,

    而我们是按照dfs序号遍历的,于是 dfn(lit)<dfn(x) ,错误。

  2. 若lit和x在不同链上上则需详细分类

    令pr为lit上一位。

    循环3个操作

    • dfn[pr]>=dfn[f] 将lit与pr连边,并弹栈。 当 dfn[pr]=dfn[f] 时退出循环。
    • dfn[pr]<dfn[f] 说明f在lit与pr间,连边f—>pr,退栈,将f进栈,退出循环。
    • 最后将x压入栈,保持dfs链。

这样的操作保证在栈中的点都在一条链上这就是维护右链。

最后将留在栈中的点依次与上一个点连边并退栈。虚树就构建完成了。

建树的复杂度为O(logn) 的 。

O(N)构造虚树

By kczno1

我做过的题里,都是读进来许多询问,之后节点总个数是O(N)的。 对每个询问,我们要将节点按dfs序排序,之后求出相邻两点的lca。 这两步都是nlogn的,也都可以离线做到O(n)。 排序,由于值域是1-n的,可以全部插到一个值域的数组里,记录是哪个询问的,再插回来就行了。 排完序后,哪些点需要求lca我们是知道的,于是可以用tarjan来求lca。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值