树上启发式合并(dsu on tree)学习笔记

树上启发式合并是什么?

树上启发式合并(dsu on tree)通过继承重儿子的信息,可以将某些合并更新答案次数为 O ( n 2 ) O(n^2) O(n2) 的问题优化至 O ( n log ⁡ n ) O(n \log n) O(nlogn)

算法过程

在普通 dfs 的基础上,继承重儿子传上来的信息。

先 dfs 轻儿子并把记录的信息清空,再 dfs 重儿子且不清空信息(继承)。随后暴力搜索轻子树内的节点更新信息。

这样做可以保证每次传上来的只有重儿子的信息,且算完当前子树的答案后,目前保留的信息只有这棵子树的。

代码:

void dfss(int x)
{
    for (int i = head[x];i;i = nxt[i])
    {
        int u = to[i];
        if (u == son[x]) continue;
        dfss(u);//递归处理轻儿子
        clr(u);//清空
    }
    if (son[x]) dfss(son[x]);
    ...//加入当前节点信息
    for (int i = head[x];i;i = nxt[i])
    {
        int u = to[i];
        if (u == son[x]) continue;
        upd(u,x);//更新答案
        add(u);//更新信息
    }
}

时间复杂度

对每一个节点,如果它是父亲的轻儿子,它所在子树就会在 dfs 父亲时被暴力更新一次。也就是说,一个点被暴力更新的次数即为它到根经过的轻边数,是 O ( log ⁡ n ) O(\log n) O(logn) 的。所以总的更新次数是 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的。

注意

为了保证时间复杂度正确,继承重儿子信息这一步要保证更新次数为 O ( 1 ) O(1) O(1)的,所以一般存信息时,要存不会因为当前节点变化而变化很大的信息。

另外,清空信息的复杂度也要注意不要爆炸。一般直接 dfs 子树清空即可。

题目

这篇文章的最后有一堆题目。

CF1923E

CF778C,甚至不用传信息

  • 27
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值