树上一些比较经典或是可能比较偏其实是自己太菜没学过不太会的内容

孩子兄弟表示法

把普通的树转化为二叉树

实现

对于一个点,如果它在原树中有儿子,则随便找一个(或按某种顺序选取)在二叉树中把它做为它的左儿子;如果在原树中有兄弟,那么随便找一个(或按某种顺序选取)在二叉树中作为它的右儿子,不断递归构造(即左孩子右兄弟)

应用

一般不需要真正建出来,在表达式树/某些树形dp中用到了这个思想

prufer序列

常用于有标号的无根树计数

  • 无根树转prufer序列

    每次选取编号最小的叶子,把它父亲记录,并把它自己删除

  • prufer序列转无根树

    设点集V=1,2,3,...,nV={1,2,3,...,n},每次取出prufer序列中最前面的元素uu,在VV中找到编号最小的没有在prufer序列中出现的元素vv,给uuvv连边然后分别删除,不断重复此过程。最后在VV中剩下两个节点,给它们连边。最终得到的就是无根树。

结论/应用

  • 任何一棵无根树都有一种prufer序列与它一一对应,反之亦然
  • 有编号无根树计数:nn2n^{n-2}
  • 有编号有根树计数:nn2n=nn1n^{n-2}*n = n^{n-1}
  • 可以均匀地随机一棵树
  • prufer序列中某个编号出现的次数就等于这个编号的节点在无根树中的度数-1
  • nn个节点的度为deg[i]deg[i]的无根树共有(n2)!i=1n(deg[i]1)!\frac{(n-2)!}{\sum_{i=1}^{n}(deg[i] - 1)!}个,因为此时prufer编码中的数字ii恰好出现

长链剖分

一种O(n)O(n)合并深度相关信息的方法:见此

这里介绍另外一种形式,用来O(nlogn)O(1)O(n\log n)-O(1)kk祖先

首先不难发现一个性质:

任意一个点的kk级祖先所在链的链长一定大于等于kk

因为如果这个点和他的kk级祖先在一条链上,那么结论显然成立。

如果不在一条链上,那么一开始这个祖先没有选择这棵子树是因为别的子树更深,故而所在链一定是大于kk的,结论仍然成立。

对于每条重链,在每条重链顶部预处理出重链顶端向上kk步之内的祖先,以及向下kk步重链上的所有点。kk为重链长度。再对每个点求出2i2^i祖先的倍增数组

考虑询问xxkk级祖先,先利用倍增数组跳2l2^l祖先,其中ll满足k2<lk\frac{k}{2}<l\le k(即kk的最高位),设剩余层数为kk',可以发现k<k2k'< \frac{k}{2}

利用之前证明的性质,我们可以发现当前节点所在链链长一定严格大于kk'

如果链头在当前节点的kk'级祖先上面,那么我们利用链头向下的数组可以得到答案,否则利用向上的数组得到答案

可以发现询问总复杂度是O(1)O(1)