树哈希学习笔记
我们用字符串哈希可以判断字符串相等,那么判断树同构呢?
两棵树同构,当且仅当存在将其中一棵树的节点编号打乱的方案,使得打乱后两棵树完全相同。
树哈希,就是把字符串哈希搬到树上来。对于两棵同构的有根树,其哈希值相同。下面介绍一种构造方式:
\[f_i=1+\sum\limits_{x\in son(i)}f_xp_{|S(x)|}
\]
其中 \(S(x)\) 表示 \(x\) 的子树中节点所构成集合,\(son(x)\) 表示 \(x\) 的儿子构成的集合,而 \(p_x\) 为一个权值。一般可以取第 \(x\) 个质数。这样 \(f_i\) 就表示以 \(i\) 为根的子树的哈希值。这样哈希有什么好处呢?这样是可以换根的。假如说儿子还有顺序,那么 \(|S(x)|\) 可以改成 \(r_x\),表示 \(x\) 是其父亲的第几个儿子。
我们知道字符串哈希可以支持获取一段字串的哈希值,那么树哈希能否支持快速获取一棵子树减去一棵更小的子树,得到的哈希值呢?我们尝试考虑上述哈希构造法则的本质。令 \(g_i=p_{|S(i)|}\) 并且 \(h_i=\sum\limits_{i\in S(x)}g_x\),那么有:
\[f_i=\sum\limits_{x\in S(i)}\dfrac{h_x}{h_i}
\]
这告诉我们,将以 \(i\) 为根的子树中,去掉以 \(j\) 为根的子树,其哈希值为 \(f_i-\dfrac{h_j}{h_i}f_j\)。同理将一棵树拼接到另一棵树上得到的哈希值也可以轻松得到。