【算法讲20:Dsu on Tree】

  • 【例一:树上数颜色】
    • · 暴力做法 ·
    • · 考虑优化 ·
  • ⌈ D s u o n T r e e ⌋ \lceil Dsu\ on\ Tree\rfloor ⌈Dsu on Tree⌋
  • 【代码】
  • 【例二: L o m s a t g e l r a l Lomsat\ gelral Lomsat gelral】

【例一:树上数颜色】

  • 【链接】
    树上数颜色 | 洛谷 U41492
  • 【题意】
    给定一棵有根树,有 n n n 个节点,每个节点有一个颜色 c i c_i ci​
    你需要求出每个节点,该节点的子树的颜色的种类数。
  • 【范围】
    1 ≤ c i ≤ n ≤ 1 0 5 1\le c_i\le n\le 10^5 1≤ci​≤n≤105

· 暴力做法 ·

  • 对于每一个节点,遍历它的子树,计算出所有颜色的数量 c n t [ c o l o r ] cnt[color] cnt[color],就能得到有多少个不同的颜色了。
  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),结果 T L E \color{red}TLE TLE

· 考虑优化 ·

  • 我们可以算出每一个节点的重儿子
    重儿子就是儿子中,子树大小最大的那一个儿子。其他的儿子都叫做轻儿子
  • 我们凭感觉,对于某一个节点,它的子树中的颜色数目的计算,可以先获取该节点的重儿子的子树的颜色数目,然后再去暴力跑其他轻儿子的子树的颜色数目,然后对这些数目进行合并
    这样子是不是快的多呢?很神奇的,我们的时间复杂度从 O ( n 2 ) O(n^2) O(n2) 变到了 O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 略证:某个节点的遍历次数等于该节点到根节点的边中轻边的数量。从深度为 d − 1 d-1 d−1 的节点经过轻边走到深度为 d d d 的节点,子树大小至少 × 2 \times 2 ×2,所以轻边个数为 O ( log ⁡ n ) O(\log n) O(logn),所以得证。

⌈ D s u o n T r e e ⌋ \lceil Dsu\ on\ Tree\rfloor ⌈Dsu on Tree⌋

  • 树上启发式合并,主要思想就是处理出每个节点的重儿子。接下来,我们保留重儿子的贡献,跑轻儿子的贡献,得到当前节点的贡献;然后,我们删掉轻儿子的贡献。
    主要是三个函数: d f s 1 ( ) dfs1() dfs1() 跑轻重儿子, d f s 2 ( ) dfs2() dfs2() 跑节点遍历, g o ( ) go() go() 增/删贡献。
  • 我们通过一些全局变量来模拟存储重儿子中的贡献值。
    然后好像就没了…

【代码】

  • 时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
    空间复杂度: O ( n ) O(n) O(n)
vector<int>V[MAX];
int co[MAX];
int sz[MAX],hson[MAX];      /// 子树大小和重儿子编号。没有重儿子则编号为0
void dfs1(int x,int f){sz[x] = 1;for(auto it : V[x]){if(it == f)continue;dfs1(it,x);sz[x] += sz[it];if(sz[it] > sz[hson[x]])hson[x] = it;}
}
int res = 0;                   /// 目前有多少种不同的颜色
int cnt[MAX],ans[MAX];          /// cnt[i] 表示颜色i的出现次数  ans[i] 表示结点编号i的答案
void go(int x,int f,int dec){cnt[co[x]] += dec;                       /// 增  / 删贡献if(dec == 1 && cnt[co[x]] == 1)res++; /// 多了一种颜色if(dec ==-1 && cnt[co[x]] == 0)res--; /// 少了一种颜色for(auto it : V[x]){if(it == f)continue;go(it,x,dec);}
}
void dfs2(int x,int f,bool del){for(auto it : V[x]){if(it == f || it == hson[x])continue;   /// 遍历轻儿子dfs2(it,x,true);}if(hson[x])dfs2(hson[x],x,false);         /// 遍历重儿子cnt[co[x]]++;if(cnt[co[x]] == 1)res++;for(auto it : V[x]){if(it == f || it == hson[x])continue;  /// 增加轻儿子贡献go(it,x,1);}ans[x] = res;if(del)go(x,f,-1);     /// 删除轻儿子贡献
}
int main()
{int n;scanf("%d",&n);for(int i = 1;i < n;++i){int ta,tb;scanf("%d%d",&ta,&tb);V[ta].push_back(tb);V[tb].push_back(ta);}for(int i = 1;i <= n;++i)scanf("%d",&co[i]);dfs1(1,1);dfs2(1,1,false);int Q;scanf("%d",&Q);while(Q--){int t;scanf("%d",&t);printf("%d\n",ans[t]);}return 0;
}

【例二: L o m s a t g e l r a l Lomsat\ gelral Lomsat gelral】

  • 【链接】
    洛谷 | CF 600E
  • 【题意】
    给定 n n n 个节点的树,每个节点的颜色为 c i c_i ci​
    a n s i ans_i ansi​ 表示编号 i i i 的子树中,所有出现次数最多的颜色的编号和
    求出 a n s 1 ∼ a n s n ans_1\sim ans_n ans1​∼ansn​
  • 【范围】
    1 ≤ c i ≤ n ≤ 1 0 5 1\le c_i\le n\le 10^5 1≤ci​≤n≤105
  • 【思路】
    和例题一差不多,仍然要计算出 c n t [ c o l o r ] cnt[color] cnt[color]
    不过我们还要存储 m x mx mx,表示目前子树的颜色的最多出现次数是多少
    然后去动态更新这个 m x mx mx,同时也要更新出 r e s res res ,意义同 a n s i ans_i ansi​
  • 【代码】
    时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
    空间复杂度: O ( n ) O(n) O(n)
vector<int>V[MAX];
int co[MAX];
int sz[MAX],hson[MAX];
void dfs1(int x,int f){sz[x] = 1;for(auto it : V[x]){if(it == f)continue;dfs1(it,x);sz[x] += sz[it];if(sz[it] > sz[hson[x]])hson[x] = it;}
}
ll mx = 0,res = 0;
ll cnt[MAX],ans[MAX];
void go(int x,int f,int dec){cnt[co[x]] += dec;if(dec == 1){        /// 增加贡献可能会增加 resif(cnt[co[x]] > mx)res = co[x],mx = cnt[co[x]];else if(cnt[co[x]] == mx)res += co[x];}for(auto it : V[x]){if(it == f)continue;go(it,x,dec);}
}
void dfs2(int x,int f,bool del){for(auto it : V[x]){if(it == f || it == hson[x])continue;dfs2(it,x,true);}if(hson[x])dfs2(hson[x],x,false);for(auto it : V[x]){if(it == f || it == hson[x])continue;go(it,x,1);}cnt[co[x]]++;if(cnt[co[x]] > mx)res = co[x],mx = cnt[co[x]];     /// 更新res mxelse if(cnt[co[x]] == mx)res += co[x];ans[x] = res;if(del)go(x,f,-1),mx = res = 0;                       /// 删除子树,mx = res = 0
}
int main()
{int n;scanf("%d",&n);for(int i = 1;i <= n;++i)scanf("%d",&co[i]);for(int i = 1;i < n;++i){int ta,tb;scanf("%d%d",&ta,&tb);V[ta].push_back(tb);V[tb].push_back(ta);}dfs1(1,1);dfs2(1,1,false);for(int i = 1;i <= n;++i)printf("%lld ",ans[i]);return 0;
}

【算法讲20:Dsu on Tree】树上数颜色 | Lomsat gelral相关推荐

  1. [dsu on tree]树上启发式合并总结(算法思想及模板附例题练习)

    文章目录 前言 树上启发式合并 引入 算法思想 时间复杂度 模板 练习 例题:CF600E Lomsat gelral solution code CF208E Blood Cousins solut ...

  2. dsu on tree 题集 + ac代码

    文章目录 **入门讲解** **[600E - Lomsat gelral](https://codeforces.ml/problemset/problem/600/E)** **[树上数颜色](h ...

  3. 【CF 600E】Lomsat gelral(树上启发式合并, dsu on tree, 静态链分治,模板题)

    Algorithm 名称:树上启发式合并, dsu on tree, 静态链分治 用处:一般用来解决一类不带修改的子树查询问题 核心思想为:利用重链剖分的性质优化子树贡献的计算. 前置知识:启发式合并 ...

  4. 【算法讲11:卡特兰数】默慈金数 | 那罗延数 | 施罗德数

    [算法讲11:卡特兰数]默慈金数 | 那罗延数 | 施罗德数 ⌈\lceil⌈卡特兰数⌋\rfloor⌋Catalan Number 引入 思考 ⌈\lceil⌈卡特兰数⌋\rfloor⌋的性质 ⌈\ ...

  5. 埃森哲杯第十六届上海大学程序设计联赛春季赛暨上海高校金马五校赛 B 合约数 (dfs+预处理)(dsu on tree)

    链接:https://ac.nowcoder.com/acm/contest/9115/B 题意:给定一棵n个节点的树,并且根节点的编号为p,第i个节点有属性值vali, 定义F(i): 在以i为根的 ...

  6. 树上启发式合并(dsu on tree)

    dsu on tree dsu \text{dsu} dsu一般指 disjoint set union \text{disjoint set union} disjoint set union,即并 ...

  7. 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree...

    原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...

  8. BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )

    树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法: ...

  9. dsu on tree入门

    先瞎扯几句 说起来我跟这个算法好像还有很深的渊源呢qwq.当时在学业水平考试的考场上,题目都做完了不会做,于是开始xjb出题.突然我想到这么一个题 看起来好像很可做的样子,然而直到考试完我都只想出来一 ...

最新文章

  1. 大数据安全“脆弱性”凸显 防护成重要课题
  2. zoj 2709 Lottery 组合数,概率,贪心 (8-F)
  3. Python 微信机器人-用itchat库向好友发送名片、转发名片实例演示
  4. 怎么样给单选按钮前面插入小图标
  5. Java的重写和重载机制
  6. LeetCode每日一题 977. 有序数组的平方
  7. Filter handling in SAP gateway
  8. centos静默安装oracle关于报错UnsatisfiedLinkError exception loading native library:njni10
  9. 软件工程网络15个人阅读作业1
  10. python3.6---之f'{}'
  11. 《测试类职位面试360度》
  12. 田汉卿 | 量化基金怎么投,才能源源不断赚钱?
  13. Linux内核源码下载
  14. java复制行_Java 复制Word表格中的行或列
  15. php计算macd,MT4里的MACD和平常所用的MACD计算公式是什么?
  16. kali下使用远程桌面连接
  17. java根据文件字符换行_java操作txt文本(一):遇到指定字符换行
  18. 多伦多大学好吗_多伦多大学留学好不好
  19. ETABS结构指标查看
  20. EEEPC专用XP系统中如何安装FN快捷键驱动?

热门文章

  1. 一种LCD屏闪问题的调试
  2. matalb编写程序实现ps的“素描滤镜”
  3. U3d引擎与资源管理
  4. 原来普洱茶还有预防头痛,减轻体重,缓解压力和失眠的作用,而且是年份久的普洱茶效果好
  5. word实现转换成图片的实现
  6. 如何获取淘宝商品类目信息,通过商品ID获取商品类目?
  7. 什么软件可以代替sc防火墙_蜂蜜和糖稀有什么区别?糖稀可以用蜂蜜代替么?...
  8. 通报1422人!论文无实质贡献挂名认定为学术不端,科技部发布新规!
  9. 企业如何制作自己的公司网站?
  10. 中医证型关联规则挖掘