带权并查集做题记录

P5092 [USACO04OPEN]Cube Stacking

对于一个立方柱,令其最上面的方块为根,其余方块在树内。

考虑维护每个方块 \(i\) 上面(不包括自身)和下面(包括自身)的方块数量 \(suf_i\)\(pre_i\)

对于将 \(x\) 立方柱移动到 \(y\) 立方柱上面的操作:

  • \(fa_y=fa_x\)
  • \(suf_y=pre_x\)
  • \(pre_x\gets pre_x+pre_y\)

进行完 \(x,y\) 的更新后,我们发现其余在树中的结点存储的信息一定是错误的。具体地,在 \(x,y\) 之间的方块的 \(pre\) 是错误的,在 \(y\) 下面的方块的 \(suf\) 是错误的。

而暴力更新复杂度会伪,不要想到启发式合并那一块儿去。

那就修改定义\(suf_x\) 表示 \(fa_x\)\(x\) 中间这一段的方块数量(包含 \(fa_x\))。

这样的更新就是正确的,但是如何得到原定义的结果呢?

观察一下我们的路径压缩,任意结点只要查找一次就会挂在根下面,而此时 \(suf\)等于原定义的结果

首先递归更新父亲,这样能保证传下来的信息正确

然后更新 \(x\) 自身:

  • \(suf_x\gets suf_x+suf_{fa_x}\)
  • \(fa_x=find(fa_x)\)

\(pre\) 还是没法搞,一种方法就是反过来以最底下的方块作为根建立一个带权并查集,不过也可以不这么做。

注意到最顶上的方块的 \(pre\)一定正确的,也就是立方柱中方块总个数知道。

于是 \(x\) 方块下面的方块数量可以转化成 \(pre_{find(x)}-suf_x\)

P2024 [NOI2001] 食物链

因为是个环,所以不妨用 \(type_i\) 表示动物 \(i\) 对于动物 \(fa_i\)相对关系。具体地,可以令 \(0\) 表示同类,\(1\) 表示吃,\(2\) 表示被吃。

更新的时候,直接相加模 \(3\),判关系的时候减一减就好了。

注意 \(fa\) 可能不存在。

因为对根没有特定要求,所以可以路径压缩。

posted @ 2021-07-12 16:38  Biadocy  阅读(43)  评论(0编辑  收藏  举报