虚树学习笔记

Tips:我们求得每个点的dfs序,然后把这些点按dfs序排序,那么他们所有的LCA肯定是排序后某相邻两点的LCA。

虚树建立的流程(bzoj2286):

1:先把每个询问点按照dfn从小到大的顺序排序。
2:维护一个栈表示当前从根出发的路径。一开始栈中只有一个元素就是根(1)。
3:枚举每一个询问点,尝试插入。
4:如果当前栈中只有一个元素1,就直接插到栈顶返回。
5:否则记当前栈顶元素为sta[upp],计算出sta[upp]和x的LCA,记作lca。
6:如果lca就是sta[upp]。在这个问题中如果一个子树的根是关键点,它的孩子就不用看了。所以这里直接返回。
7:否则判断当前栈维护的路径是否和当前点脱离。

while(upp > 1 && dfn[sta[upp-1]] >= dfn[lca]) Add(sta[upp-1], sta[upp]),upp--;

这里就是把栈回退,一直退到能接上这个点的地方。
8:如果退不到那个点,就把lca当做这个点。

if (lca != sta[upp]) Add(lca, sta[upp]), sta[upp] = lca;

9:最后留下的栈就是剩下的那一条路径,再把这一条路径加上就好了。

while (upp > 1) Add(sta[upp - 1], sta[upp]), upp--;

然后本题的虚树就建好了。这里等于把树上的一些长链压缩了,只保留我们需要的路径上最小值这个有用的信息。

复杂度说明:

考虑我们每两个点最多会增加一个LCA。反证,加上x和y有lca1,x和z有lca2。假设dep[lca1]<dep[lca2],那么y和z的LCA就是lca1.重复出现故矛盾,所以每两个点最多增加一个LCA。所以虚树的总点数是 2 Σ ( k i ) 2\Sigma(k_i) 2Σ(ki)的。

一些技巧:

1:然后对于很多题目建虚树都要建多次,那么 邻接表/vector 的同学都要清空 head/vector ,如果 memset/一个个枚举clear 那肯
定会T的,我往往都会在树形dp时用完边后进行清空,就非常高效了。

loj2219

首先考虑如果给定这k个点怎么办。 f 0 ( i ) f_0(i) f0(i)表示 i i i为根的子树里面关键点的数目, f 1 ( i ) f_1(i) f1(i)表示以 i i i为根的子树里面,以关键点i的最短路径(如果i不是关键点就是一个不可能的值)。 f 2 ( i ) f_2(i) f2(i)表示最长的。

f 0 f_0 f0的转移就是直接加。这里可以直接统计答案。考虑 i i i的子树里面的这些点要形成点对的话一定要向外连,此时的点对数目就是 f 0 ( i ) ∗ ( k − f 0 ( i ) ) f_0(i)*(k-f_0(i)) f0(i)(kf0(i))。每一对对答案的贡献就是 d e p [ y ] − d e p [ x ] dep[y] -dep[x] dep[y]dep[x]

f 1 f_1 f1 f 2 f_2 f2的转移一样的。都是按照顺序枚举子树。

 f1[x] = min(f1[x], f1[y] + (dep[y] - dep[x]));
 f2[x] = max(f2[x], f2[y] + (dep[y] - dep[x]));

这里统计答案的时候要注意,由于路径可以以 i i i作为LCA,所以要这样统计:

 Min = min(Min, f1[x] + f1[y] + (dep[y] - dep[x]));
 Max = max(Max, f2[x] + f2[y] + (dep[y] - dep[x]));

也就是考虑一个来接上。类似点分治的一种统计法,不重不漏的。

这里求的虚树稍微和上一题有一点不一样。上一题如果 l c a = = s t a [ u p p ] lca==sta[upp] lca==sta[upp]就直接返回了。这里需要把 x x x入栈再返回。因为上一题的问题,如果 l c a = = s t a [ u p p ] lca==sta[upp] lca==sta[upp]的话,切上面一定比切下面更加优越,所以下边就无所谓了。但是这一题要统计路径信息,所以不能这样省略。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值