BSOJ6756口胡

ETT模板。

题意:维护一颗动态树,支持:

换父亲,换根,子树乘,子树求和。

ETT 实际上是用平衡树去维护这颗树的欧拉环游序。但是因为是欧拉环游序,所以是可以随意循环位移的。为了方便,我们从 根节点第一次出现的位置 断开这个欧拉环游序。(欧拉环游序实际上应该是一条环,大部分时候我们都是人为地从根节点处断开了并且加了一个多余的节点进去)

有了这个结构,子树乘与子树和自然能转化成区间和与区间乘。我们只需要维护断开的位置和每个节点子树的区间即可。

根节点是个例外,因为我们砍掉了根节点退出 DFS 时的那个节点。但是因为根节点代表全局,所以可以特判掉。修改和询问都是如此。

换根相当于平移区间。换爸爸也是如此。问题在于如何找到每个节点在 ETT 上对应的区间。

化简问题,我们寻找每个节点第一次出现的位置。

我们记录每个节点第一次出现的位置,假设为 \(fir[u]\),每次询问的时候(可能换根之后这个节点就不是第一次出现的了)通过这个位置找到第一次出现的位置。

我们记录每个节点在 ETT 上出现的所有位置,设为 \(p[u][1\sim r[u]]\)。记录一个 \(dis[u][i]\) 表示 \(p[u][i]\) 在 ETT 上向右走到 \(p[u][(i\bmod r[u])+1]\) 的长度。每次先询问 \(fir[u]\) 在 ETT 上的“下标”,然后在 \(dis[u]\) 上二分即可。

可以发现,换根操作是不会改变 \(dis[u]\) 的,而换父亲操作只会改变两个节点的 \(dis\),并且操作量都是 \(O(1)\) 的。我们只需要使用平衡树维护 \(p\)\(dis\) 即可。每次换父亲的时候直接询问 \(dis\) 即可。

复杂度是 \(O(m\log n)\) 的,但是明显并不是很好写。。。

posted @ 2022-04-11 09:18  Prean  阅读(43)  评论(0编辑  收藏  举报
var canShowAdsense=function(){return !!0};