链接:
http://codeforces.com/problemset/problem/600/E
题意:
You are given a rooted tree with root in vertex 1. Each vertex is coloured in some colour.
Let's call colour c dominating in the subtree of vertex v if there are no other colours that appear in the subtree of vertex v more times than colour c. So it's possible that two or more colours will be dominating in the subtree of some vertex.
The subtree of vertex v is the vertex v and all other vertices that contains vertex v in each path to the root.
求一个子数的众数和
思路:
考虑暴力算法,每次计算清零,复杂度n^2.
启发式合并,先处理出每个字节点的重儿子,和子树大小。
我们优先遍历每个子树的轻儿子,但是每次处理完后不保存记录的信息。
最后一次遍历重儿子,因为只剩重儿子,所以这个重儿子不需要清楚信息。
再统计子树的根节点时还要计算一边轻儿子。
总复杂度nlogn。不会证(逃
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+10;
const int MOD = 1e9+7;
const int INF = 1e9+10;
int n, num;
int size[MAXN], son[MAXN], dfn[MAXN];
int a[MAXN], b[MAXN], c[MAXN], col[MAXN];
LL mx, now, ans[MAXN];
vector<int> G[MAXN];
void dfs(int x, int fa)
{
//计算子树大小,找重儿子
size[x] = 1, dfn[x] = ++num;
for (auto &y: G[x])
{
if (y == fa) continue;
dfs(y, x);
size[x] += size[y];
son[x] = size[y] > size[son[x]] ? y : son[x];
}
}
void add(int x)
{
if (++c[x] > mx) mx = c[x], now = 0;
if (c[x] == mx) now += x;
}
void solve(int x, int fa, int k)
{
for (auto &y: G[x]) if (y != fa && y != son[x])
solve(y, x, 0);
if (son[x]) solve(son[x], x, 1);
for (auto &y: G[x]) if (y != fa && y != son[x])
for (int i = 0;i < size[y];i++) add(a[dfn[y]+i]);
add(a[dfn[x]]);
ans[x] = now;
if (!k) for (int i = mx = now = 0;i < size[x];i++) c[a[dfn[x]+i]] = 0;
}
int main()
{
//dsu on tree 启发式合并
ios::sync_with_stdio(stdin);
cin.tie(0), cout.tie(0);
num = 0;
cin >> n;
for (int i = 1;i <= n;i++)
cin >> col[i];
for (int i = 1;i < n;i++)
{
int u, v;
cin >> u >> v;
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
for (int i = 1;i <= n;i++) a[dfn[i]] = col[i];
solve(1, 0, 1);
for (int i = 1;i <= n;i++)
cout << ans[i] << ' ' ;
return 0;
}