【CF600E】Lomsat gelral——树上启发式合并
(题面来自luogu)
题意翻译
一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和。
ci <= n <= 1e5
裸题。统计时先扫一遍得到出现次数最大值,然后再扫一遍看哪个颜色的出现次数与mxCnt相等。注意用一个bool数组判重,清空轻儿子贡献时要顺手把bool数组也打成false。(这是错的,请看下一份代码)
代码:
- #include <iostream>
- #include <cstdio>
- #include <cctype>
- #define maxn 100010
- using namespace std;
- template <typename T>
- void read(T &x) {
- x = 0;
- char ch = getchar();
- while (!isdigit(ch))
- ch = getchar();
- while (isdigit(ch))
- x = x * 10 + (ch ^ 48), ch = getchar();
- }
- int n;
- int head[maxn], top;
- struct E {
- int to, nxt;
- } edge[maxn << 1];
- inline void insert(int u, int v) {
- edge[++top] = (E) {v, head[u]};
- head[u] = top;
- }
- int son[maxn], size[maxn];
- long long ans[maxn];
- void dfs1(int u, int pre) {
- size[u] = 1;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre) continue;
- dfs1(v, u);
- size[u] += size[v];
- if (size[v] > size[son[u]])
- son[u] = v;
- }
- return;
- }
- int color[maxn], cnt[maxn], sum;
- int curSon, mxCnt;
- bool vis[maxn];
- void calc(int u, int pre, bool op) {
- op ? (++cnt[color[u]], mxCnt = max(mxCnt, cnt[color[u]])) : (--cnt[color[u]], vis[color[u]] = false);
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre || v == curSon)
- continue;
- calc(v, u, op);
- }
- }
- void stats(int u, int pre) {
- if (cnt[color[u]] == mxCnt && !vis[color[u]])
- sum += color[u], vis[color[u]] = true;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v != pre)
- stats(v, u);
- }
- return;
- }
- void dsu(int u, int pre, bool op) {
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre || v == son[u])
- continue;
- dsu(v, u, 0);
- }
- if (son[u])
- dsu(son[u], u, 1), curSon = son[u];
- mxCnt = 0;
- calc(u, pre, 1);
- stats(u, pre);
- ans[u] = sum;
- curSon = 0;
- if (!op) {
- sum = 0;
- calc(u, pre, 0);
- }
- }
- int main() {
- read(n);
- for (int i = 1; i <= n; ++i)
- read(color[i]);
- int u, v;
- for (int i = 1; i < n; ++i) {
- read(u), read(v);
- insert(v, u), insert(u, v);
- }
- dfs1(1, 0);
- dsu(1, 0, 1);
- for (int i = 1; i <= n; ++i)
- printf("%I64d ", ans[i]);
- return 0;
- }
(交这个题的时候cf炸了……才不是因为我TLE呢
--------------------------
然而果然出了锅,昨天CF评测机大概是被这个弱智错误笑死的……
重测了下,上面那份代码是错的,原因是没有考虑重儿子内的最大出现次数。然而原思路越改越复杂,后来想了想,每遍历到重复的颜色其出现次数都会+1,因此不用判重,从每个点统计时扫一遍就好了。
代码:
- #include <iostream>
- #include <cstdio>
- #include <cctype>
- #define maxn 100010
- using namespace std;
- template <typename T>
- void read(T &x) {
- x = 0;
- char ch = getchar();
- while (!isdigit(ch))
- ch = getchar();
- while (isdigit(ch))
- x = x * 10 + (ch ^ 48), ch = getchar();
- }
- int n;
- int head[maxn], top;
- struct E {
- int to, nxt;
- } edge[maxn << 1];
- inline void insert(int u, int v) {
- edge[++top] = (E) {v, head[u]};
- head[u] = top;
- }
- int son[maxn], size[maxn];
- long long ans[maxn];
- void dfs1(int u, int pre) {
- size[u] = 1;
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre) continue;
- dfs1(v, u);
- size[u] += size[v];
- if (size[v] > size[son[u]])
- son[u] = v;
- }
- return;
- }
- int color[maxn], cnt[maxn];
- long long sum;
- int curSon, mxCnt;
- void calc(int u, int pre, int val) {
- cnt[color[u]] += val;
- if (val == 1) {
- if (cnt[color[u]] > mxCnt)
- mxCnt = cnt[color[u]], sum = color[u];
- else if (cnt[color[u]] == mxCnt)
- sum += color[u];
- }
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre || v == curSon)
- continue;
- calc(v, u, val);
- }
- }
- void dsu(int u, int pre, bool op) {
- for (int i = head[u]; i; i = edge[i].nxt) {
- int v = edge[i].to;
- if (v == pre || v == son[u])
- continue;
- dsu(v, u, 0);
- }
- if (son[u])
- dsu(son[u], u, 1), curSon = son[u];
- calc(u, pre, 1);
- ans[u] = sum;
- curSon = 0;
- if (!op) {
- mxCnt = sum = 0;
- calc(u, pre, -1);
- }
- }
- int main() {
- read(n);
- for (int i = 1; i <= n; ++i)
- read(color[i]);
- int u, v;
- for (int i = 1; i < n; ++i) {
- read(u), read(v);
- insert(v, u), insert(u, v);
- }
- dfs1(1, 0);
- dsu(1, 0, 1);
- for (int i = 1; i <= n; ++i)
- printf("%I64d ", ans[i]);
- return 0;
- }
【CF600E】Lomsat gelral——树上启发式合并的更多相关文章
- CF600E Lomsat gelral 树上启发式合并
题目描述 有一棵 \(n\) 个结点的以 \(1\) 号结点为根的有根树. 每个结点都有一个颜色,颜色是以编号表示的, \(i\) 号结点的颜色编号为 \(c_i\). 如果一种颜色在以 \(x\) ...
- CF EDU - E. Lomsat gelral 树上启发式合并
学习:http://codeforces.com/blog/entry/44351 E. Lomsat gelral 题意: 给定一个以1为根节点的树,每个节点都有一个颜色,问每个节点的子树中,颜色最 ...
- CF 600 E Lomsat gelral —— 树上启发式合并
题目:http://codeforces.com/contest/600/problem/E 看博客:https://blog.csdn.net/blue_kid/article/details/82 ...
- CF600E Lomsat gelral——线段树合并/dsu on tree
题目描述 一棵树有$n$个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. 这个题意是真的窒息...具体意思是说,每个节点有一个颜色,你要找的是每个子树中颜色的众数 ...
- Codeforces 600 E. Lomsat gelral (dfs启发式合并map)
题目链接:http://codeforces.com/contest/600/problem/E 给你一棵树,告诉你每个节点的颜色,问你以每个节点为根的子树中出现颜色次数最多的颜色编号和是多少. 最容 ...
- CF600E:Lomsat gelral(线段树合并)
Description 一棵树有n个结点,每个结点都是一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号的和. Input 第一行一个$n$.第二行$n$个数字是$c[i]$.后面$n-1$ ...
- 【学习笔记/题解】树上启发式合并/CF600E Lomsat gelral
题目戳我 \(\text{Solution:}\) 树上启发式合并,是对普通暴力的一种优化. 考虑本题,最暴力的做法显然是暴力统计每一次的子树,为了避免其他子树影响,每次统计完子树都需要清空其信息. ...
- Codeforces 600E - Lomsat gelral(树上启发式合并)
600E - Lomsat gelral 题意 给出一颗以 1 为根的树,每个点有颜色,如果某个子树上某个颜色出现的次数最多,则认为它在这课子树有支配地位,一颗子树上,可能有多个有支配的地位的颜色,对 ...
- [Codeforces600E] Lomsat gelral(树上启发式合并)
[Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...
随机推荐
- 痞子衡嵌入式:基于恩智浦i.MXRT1010的MP3音乐播放器(RT-Mp3Player)设计
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是基于i.MXRT1011的MP3播放器参考设计. i.MXRT1011是恩智浦i.MXRT四位数系列的入门型号,虽然是入门级,可也是50 ...
- Error response from daemon: conflict: unable to delete a2f2e369e78e (cannot be forced) - image has dependent child images
错误现象: Error response from daemon: conflict: unable to delete a2f2e369e78e (cannot be forced) - image ...
- Mysql优化建议
Mysql优化建议: (1)CPU要更快,而不是更多.因为mysql不支持多个处理器并发处理一条sql,所以正常情况下不需要考虑更多的CPU.当然,你的系统中的对mysql的并发很高时,多核可以解决一 ...
- selenium中的三种等待方式
1.强制等待,采用的time.sleep,然后后面加上要等待的时间: 2.隐性等待implicitly_wait,隐性等待设定后,会对之后的所有代码生效,会在设定的时间之内,不停的去查找元素,如果找到 ...
- CodeForces 916D Jamie and To-do List
题意 你需要维护一个任务列表,有 \(q\) 次操作,每次操作形如以下四种: set a x:设置任务 \(a\) 的优先级为 \(x\),如果任务列表中没有 \(a\) 则加进来. remove a ...
- java中常见的六种线程池详解
之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的六种线程池如 ...
- Scala-1-字符处理
// s插值val s = s"a = $a, b = $b"val s = s"a = ${a*2}, b = ${b*3}" // 顶格 及 插值val s ...
- .NetMvc从http或本地下载pdf文件
1.帮助类 1 public static class PdfHelper 2 { 3 #region 从http链接下载 4 public static void Download(string u ...
- Spring Boot 2.4 正式发布,重大调整!!!
大家周末愉快啊,Spring Boot 2.3.5 没发布几天,你看,还是 1 周前发布的: 昨天又有粉丝留言说 Spring Boot 2.4.0 已经发布了: 我了个去,栈长赶紧跑到 Spring ...
- php将富文本内容图片上传到oss并替换
/** * php 提取html中图片并替换 */ //要替换的内容 //提取图片路径的src的正则表达式 $match_str = '/(<img([^>]*)\s*src=(\'|\& ...