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.
InputThe 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.
OutputPRint n integers — the sums of dominating colours for each vertex.
Examplesinput41 2 3 41 22 32 4output10 9 3 4input151 2 3 1 2 3 3 1 1 3 2 2 1 2 31 21 31 41 141 152 52 62 73 83 93 104 114 124 13output6 5 4 3 2 3 3 1 1 3 2 2 1 2 3题目大意:求每个点的子树中颜色的出现数量最多的颜色的和。
题解:dsu on the tree
树上启发式合并。其实是一个很暴力的做法,用来解决统计树上一个节点的子树中具有某种特征的节点数,或者子树中的某个值。
做法非常的暴力,就是如果是轻儿子,每次统计完了就将影响消除,如果是重儿子就保留。每次统计答案的时候,先计算轻儿子,在计算中儿子。
最后均摊的时间复杂度是O(nlogn),时间复杂度的证明我也不太会,想明白了再来写。。。。。
#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define N 200003#define LL long long using namespace std;int n,m,point[N],v[N],nxt[N],mark[N];int size[N],son[N],tot;LL cx,sum,num[N],ans[N],col[N];void add(int x,int y){ tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;}void solve(int x,int f){ size[x]=1; for (int i=point[x];i;i=nxt[i]) { if (v[i]==f) continue; solve(v[i],x); size[x]+=size[v[i]]; if (size[v[i]]>size[son[x]]) son[x]=v[i]; }}void calc(int x,int f,int val){ num[col[x]]+=(LL)val; if (val>0&&num[col[x]]>=cx) { if (num[col[x]]>cx) sum=0,cx=num[col[x]]; sum+=(LL)col[x]; } for (int i=point[x];i;i=nxt[i]) if (v[i]!=f&&!mark[v[i]]) calc(v[i],x,val);}void dfs(int x,int f,bool k=0){ for (int i=point[x];i;i=nxt[i]) if (v[i]!=f&&v[i]!=son[x]) dfs(v[i],x,0); if (son[x]) dfs(son[x],x,1),mark[son[x]]=1; calc(x,f,1); ans[x]=sum; if (son[x]) mark[son[x]]=0; if (!k) calc(x,f,-1),cx=sum=0;}int main(){ freopen("a.in","r",stdin); freopen("my.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%I64d",&col[i]); for (int i=1;i<n;i++) { int x,y; scanf("%d%d",&x,&y); add(x,y); } solve(1,0); dfs(1,0,0); for (int i=1;i<=n;i++) printf("%I64d ",ans[i]); printf("/n");}
新闻热点
疑难解答