Codeforces 600.E Lomsat gelral
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.
For each vertex v find the sum of all dominating colours in the subtree of vertex v.
The first line contains integer n (1 ≤ n ≤ 105) — the number of vertices in the tree.
The second line contains n integers ci (1 ≤ ci ≤ n), ci — the colour of the i-th vertex.
Each of the next n - 1 lines contains two integers xj, yj (1 ≤ xj, yj ≤ n) — the edge of the tree. The first vertex is the root of the tree.
Print n integers — the sums of dominating colours for each vertex.
4
1 2 3 4
1 2
2 3
2 4
10 9 3 4
15
1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13
6 5 4 3 2 3 3 1 1 3 2 2 1 2 3
题目大意:求每个点的子树中出现次数最多的颜色的编号和.
分析:dsu on tree裸题.
先把每个点的重儿子处理出来.然后从根开始dfs处理.先dfs轻儿子,递归回来时会把贡献给清除掉,然后dfs重儿子,重儿子的贡献不会被清除. 接着计算轻儿子子树的贡献,如果当前子树是父亲的轻子树,则删除当前子树的贡献.
为什么要先dfs轻儿子?因为想要保证当前记录的答案只有当前子树的答案,不包含其他子树的答案.每次dfs轻儿子后都会清除贡献,而dfs重儿子不会.所以先dfs重儿子可能会计算其它子树的答案.
每个节点会被计算O(log n)次,总复杂度O(nlogn).
这个算法是有局限性的,它是用来解决无修改统计子树答案的题,也就是说题目必须满足:1.没有修改 2.只查询子树的答案.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const ll maxn = 100010; ll n,a[maxn],ans[maxn],head[maxn],to[maxn * 2],nextt[maxn * 2],tot = 1,son[maxn],sizee[maxn],num[maxn],maxx,vis[maxn]; struct node { ll x,v; } e[maxn]; void add(ll x,ll y) { to[tot] = y; nextt[tot] = head[x]; head[x] = tot++; } void dfs1(ll u,ll fa) { sizee[u] = 1; for (ll i = head[u]; i; i = nextt[i]) { ll v = to[i]; if (v == fa) continue; dfs1(v,u); sizee[u] += sizee[v]; if (sizee[v] > sizee[son[u]]) son[u] = v; } } void update(ll u,ll fa,ll v) { ll &c = num[a[u]]; e[c].x--; e[c].v -= a[u]; c += v; e[c].x++; e[c].v += a[u]; if (v == 1) maxx = max(maxx,c); else if (!e[maxx].x) maxx--; for (ll i = head[u]; i; i = nextt[i]) { ll vv = to[i]; if (vv == fa || vis[vv]) continue; update(vv,u,v); } } void dfs2(ll u,ll fa,ll flag) { for (ll i = head[u]; i; i = nextt[i]) { ll v = to[i]; if (v == fa || v == son[u]) continue; dfs2(v,u,0); } if (son[u]) dfs2(son[u],u,1),vis[son[u]] = 1; update(u,fa,1); ans[u] = e[maxx].v; vis[son[u]] = 0; if (flag == 0) update(u,fa,-1); } int main() { scanf("%I64d",&n); for (ll i = 1; i <= n; i++) scanf("%I64d",&a[i]); for (ll i = 1; i < n; i++) { ll x,y; scanf("%I64d%I64d",&x,&y); add(x,y); add(y,x); } dfs1(1,0); dfs2(1,0,1); for (ll i = 1; i <= n; i++) printf("%I64d ",ans[i]); return 0; }