(题面来自luogu)

题意翻译

一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。

ci <= n <= 1e5

  裸题。统计时先扫一遍得到出现次数最大值,然后再扫一遍看哪个颜色的出现次数与mxCnt相等。注意用一个bool数组判重,清空轻儿子贡献时要顺手把bool数组也打成false。(这是错的,请看下一份代码)

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cctype>
  4. #define maxn 100010
  5. using namespace std;
  6. template <typename T>
  7. void read(T &x) {
  8. x = 0;
  9. char ch = getchar();
  10. while (!isdigit(ch))
  11. ch = getchar();
  12. while (isdigit(ch))
  13. x = x * 10 + (ch ^ 48), ch = getchar();
  14. }
  15. int n;
  16. int head[maxn], top;
  17. struct E {
  18. int to, nxt;
  19. } edge[maxn << 1];
  20. inline void insert(int u, int v) {
  21. edge[++top] = (E) {v, head[u]};
  22. head[u] = top;
  23. }
  24. int son[maxn], size[maxn];
  25. long long ans[maxn];
  26. void dfs1(int u, int pre) {
  27. size[u] = 1;
  28. for (int i = head[u]; i; i = edge[i].nxt) {
  29. int v = edge[i].to;
  30. if (v == pre) continue;
  31. dfs1(v, u);
  32. size[u] += size[v];
  33. if (size[v] > size[son[u]])
  34. son[u] = v;
  35. }
  36. return;
  37. }
  38. int color[maxn], cnt[maxn], sum;
  39. int curSon, mxCnt;
  40. bool vis[maxn];
  41. void calc(int u, int pre, bool op) {
  42. op ? (++cnt[color[u]], mxCnt = max(mxCnt, cnt[color[u]])) : (--cnt[color[u]], vis[color[u]] = false);
  43. for (int i = head[u]; i; i = edge[i].nxt) {
  44. int v = edge[i].to;
  45. if (v == pre || v == curSon)
  46. continue;
  47. calc(v, u, op);
  48. }
  49. }
  50. void stats(int u, int pre) {
  51. if (cnt[color[u]] == mxCnt && !vis[color[u]])
  52. sum += color[u], vis[color[u]] = true;
  53. for (int i = head[u]; i; i = edge[i].nxt) {
  54. int v = edge[i].to;
  55. if (v != pre)
  56. stats(v, u);
  57. }
  58. return;
  59. }
  60. void dsu(int u, int pre, bool op) {
  61. for (int i = head[u]; i; i = edge[i].nxt) {
  62. int v = edge[i].to;
  63. if (v == pre || v == son[u])
  64. continue;
  65. dsu(v, u, 0);
  66. }
  67. if (son[u])
  68. dsu(son[u], u, 1), curSon = son[u];
  69. mxCnt = 0;
  70. calc(u, pre, 1);
  71. stats(u, pre);
  72. ans[u] = sum;
  73. curSon = 0;
  74. if (!op) {
  75. sum = 0;
  76. calc(u, pre, 0);
  77. }
  78. }
  79. int main() {
  80. read(n);
  81. for (int i = 1; i <= n; ++i)
  82. read(color[i]);
  83. int u, v;
  84. for (int i = 1; i < n; ++i) {
  85. read(u), read(v);
  86. insert(v, u), insert(u, v);
  87. }
  88. dfs1(1, 0);
  89. dsu(1, 0, 1);
  90. for (int i = 1; i <= n; ++i)
  91. printf("%I64d ", ans[i]);
  92. return 0;
  93. }

   (交这个题的时候cf炸了……才不是因为我TLE呢

--------------------------

  然而果然出了锅,昨天CF评测机大概是被这个弱智错误笑死的……

  重测了下,上面那份代码是错的,原因是没有考虑重儿子内的最大出现次数。然而原思路越改越复杂,后来想了想,每遍历到重复的颜色其出现次数都会+1,因此不用判重,从每个点统计时扫一遍就好了。

代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cctype>
  4. #define maxn 100010
  5. using namespace std;
  6. template <typename T>
  7. void read(T &x) {
  8. x = 0;
  9. char ch = getchar();
  10. while (!isdigit(ch))
  11. ch = getchar();
  12. while (isdigit(ch))
  13. x = x * 10 + (ch ^ 48), ch = getchar();
  14. }
  15. int n;
  16. int head[maxn], top;
  17. struct E {
  18. int to, nxt;
  19. } edge[maxn << 1];
  20. inline void insert(int u, int v) {
  21. edge[++top] = (E) {v, head[u]};
  22. head[u] = top;
  23. }
  24. int son[maxn], size[maxn];
  25. long long ans[maxn];
  26. void dfs1(int u, int pre) {
  27. size[u] = 1;
  28. for (int i = head[u]; i; i = edge[i].nxt) {
  29. int v = edge[i].to;
  30. if (v == pre) continue;
  31. dfs1(v, u);
  32. size[u] += size[v];
  33. if (size[v] > size[son[u]])
  34. son[u] = v;
  35. }
  36. return;
  37. }
  38. int color[maxn], cnt[maxn];
  39. long long sum;
  40. int curSon, mxCnt;
  41. void calc(int u, int pre, int val) {
  42. cnt[color[u]] += val;
  43. if (val == 1) {
  44. if (cnt[color[u]] > mxCnt)
  45. mxCnt = cnt[color[u]], sum = color[u];
  46. else if (cnt[color[u]] == mxCnt)
  47. sum += color[u];
  48. }
  49. for (int i = head[u]; i; i = edge[i].nxt) {
  50. int v = edge[i].to;
  51. if (v == pre || v == curSon)
  52. continue;
  53. calc(v, u, val);
  54. }
  55. }
  56. void dsu(int u, int pre, bool op) {
  57. for (int i = head[u]; i; i = edge[i].nxt) {
  58. int v = edge[i].to;
  59. if (v == pre || v == son[u])
  60. continue;
  61. dsu(v, u, 0);
  62. }
  63. if (son[u])
  64. dsu(son[u], u, 1), curSon = son[u];
  65. calc(u, pre, 1);
  66. ans[u] = sum;
  67. curSon = 0;
  68. if (!op) {
  69. mxCnt = sum = 0;
  70. calc(u, pre, -1);
  71. }
  72. }
  73. int main() {
  74. read(n);
  75. for (int i = 1; i <= n; ++i)
  76. read(color[i]);
  77. int u, v;
  78. for (int i = 1; i < n; ++i) {
  79. read(u), read(v);
  80. insert(v, u), insert(u, v);
  81. }
  82. dfs1(1, 0);
  83. dsu(1, 0, 1);
  84. for (int i = 1; i <= n; ++i)
  85. printf("%I64d ", ans[i]);
  86. return 0;
  87. }

【CF600E】Lomsat gelral——树上启发式合并的更多相关文章

  1. CF600E Lomsat gelral 树上启发式合并

    题目描述 有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树. 每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\)​. 如果一种颜色在以 \(x\) ...

  2. CF EDU - E. Lomsat gelral 树上启发式合并

    学习:http://codeforces.com/blog/entry/44351 E. Lomsat gelral 题意: 给定一个以1为根节点的树,每个节点都有一个颜色,问每个节点的子树中,颜色最 ...

  3. CF 600 E Lomsat gelral —— 树上启发式合并

    题目:http://codeforces.com/contest/600/problem/E 看博客:https://blog.csdn.net/blue_kid/article/details/82 ...

  4. CF600E Lomsat gelral——线段树合并/dsu on tree

    题目描述 一棵树有$n$个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. 这个题意是真的窒息...具体意思是说,每个节点有一个颜色,你要找的是每个子树中颜色的众数 ...

  5. Codeforces 600 E. Lomsat gelral (dfs启发式合并map)

    题目链接:http://codeforces.com/contest/600/problem/E 给你一棵树,告诉你每个节点的颜色,问你以每个节点为根的子树中出现颜色次数最多的颜色编号和是多少. 最容 ...

  6. CF600E:Lomsat gelral(线段树合并)

    Description 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. Input 第一行一个$n$.第二行$n$个数字是$c[i]$.后面$n-1$ ...

  7. 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral

    题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...

  8. Codeforces 600E - Lomsat gelral(树上启发式合并)

    600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...

  9. [Codeforces600E] Lomsat gelral(树上启发式合并)

    [Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...

随机推荐

  1. C语言,产生一组数字,并将其写入txt文档中

    #include<stdio.h> /*产生一组连续的数字,并将其写到txt文档中*/ /*说明:本程序在在win10 系统64位下用Dev-C++ 5.11版本编译器编译的*/int m ...

  2. Spring 5的最后一个特性版本5.3发布,4.3将于12月终止维护

    10月27日,Spring Framework团队宣布了5.3版本正式GA,Spring用户可以在repo.spring.io和Maven Central上获取到最新版本的依赖包. JDK的版本支持 ...

  3. 部署LNMP环境

    1.安装nginx yum -y install gcc pcre-devel openssl-devel tar xf nginx-1.16.1.tar.gz cd nginx-1.16.1/ ./ ...

  4. NLP文本多标签分类---HierarchicalAttentionNetwork

    最近一直在做多标签分类任务,学习了一种层次注意力模型,基本结构如下: 简单说,就是两层attention机制,一层基于词,一层基于句. 首先是词层面: 输入采用word2vec形成基本语料向量后,采用 ...

  5. 导入tensorflow.出现importError: DLL load failed: 找不到指定的模块。

    导入tensorflow.出现importError: DLL load failed: 找不到指定的模块. 原因 这是由于windows上没有相应的动态链接库导致的,tensorflow依赖很多c+ ...

  6. Miller-Rabin 素数检验算法

    算法简介 Miller-Rabin算法,这是一个很高效的判断质数的方法,可以在用\(O(logn)\) 的复杂度快速判断一个数是否是质数.它运用了费马小定理和二次探测定理这两个筛质数效率极高的方法. ...

  7. Raft算法原理剖析

    一.复制状态机(replicated state machine) Raft协议可以使得一个集群的服务器组成复制状态机,在详细了解Raft算法之前,我们先来了解一下什么是复制状态机.一个分布式的复制状 ...

  8. python求平均数及打印出低于平均数的值列表

    刚学Python的时候还是要多动手进行一些小程序的编写,要持续不断的进行,知识才能掌握的牢.今天就讲一下Python怎么求平均数,及打印出低于平均数的数值列表 方法一: scores1 =  [91, ...

  9. Centos8防火墙设置

    1.centos中firewalld与iptables centos7以前的版本默认使用iptables服务进行管理防火墙规则.centos7以及其以上版本默认使用firewalld服务管理防火墙.所 ...

  10. Dynamic 365 学习(1)

    一 创建解决方案 1.点击下拉菜单 2.找到设置并选择 3.点击解决方案 进入解决方案  该页面会显示你的所有的解决方案  你新建之后的可以在这里进行查看,也可以新增 删除  ... 这里我们先新建一 ...