(题面来自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;
- }