【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 ...
随机推荐
- JUC---05线程间通信(一)
一.普通的线程间通信 1.synchronized实现 package com.jenne.mydemo; class ShareDataOne { private int number = 0; p ...
- MYSQL 那些事
1.一条update语句 1.先通过引擎找到对应的行数据,并加锁 2.对行数据进行修改并调用引擎接口修改这条数据,然后释放锁(此时并没有把数据在磁盘上做出修改) 3.redo log在内存中生成这条u ...
- 直接理解转置卷积(Transposed convolution)的各种情况
使用GAN生成图像必不可少的层就是上采样,其中最常用的就是转置卷积(Transposed Convolution).如果把卷积操作转换为矩阵乘法的形式,转置卷积实际上就是将其中的矩阵进行转置,从而产生 ...
- Flask常用API
Flask常用API 1.os 拼接路径:pathname = os.path.join(basepath, filename) 获得文件名后缀:suffix = os.path.splitext ...
- windows下redis的PHP扩展安装
1.查看已安装PHP的信息,打印phpinfo(); 主要看三个信息:PHP版本,是否线程安全(TS或NTS),系统是x64还是x86.用以确定扩展文件的版本. 2.需要php_redis.dll这个 ...
- Python + Appium 自动化操作微信入门看这一篇就够了
简介 Appium 是一个开源的自动化测试工具,支持 Android.iOS 平台上的原生应用,支持 Java.Python.PHP 等多种语言. Appium 封装了 Selenium,能够为用户提 ...
- 微信小程序授权页面
这里也是比较简单的 直接复制粘贴就可以用,可能图片位置不对.. <template> <view id="imporwer"> <image src= ...
- 「SHOI2014」三叉神经树
「SHOI2014」三叉神经树 给你一颗由\(n\)个非叶子结点和\(2n+1\)个叶子结点构成的完全三叉树,每个叶子结点有一个输出:\(0\)或\(1\),每个非叶子结点的输出为自己的叶子结点中较多 ...
- XJOI 夏令营501-511NOIP训练14 砍树(2)
小A是小B家的园丁.小B的家里有n棵树,第i棵树的横坐标为i.一天,小B交给小A一个任务,让他降低自己家中的某些树木的高度.这个任务对小A来说十分简单,因为他有一把极其锋利的斧头和一门独门砍树秘籍,能 ...
- Cuda常用概念及注意点
线程的索引计算 只需要知并行线程的初始索引,以及如何确定递增的量值,我们希望每个并行线程从不同的索引开始,因此就需要对线程索引和线程块索引进行线性化,每个线程的其实索引按照以下公式来计算: int t ...