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
Analysis
Emmmm据说出题人搞出了DSU on Trees 还拿来出题了
(好在我没打这一场)
顺路解释什么是Dsu on Tree
首先我们要解决的问题是诸如此类的:在一棵树上,对每一个结点的子树进行计数(比如符合条件的结点的数量)
如果这个东西出的坑一点,我们(啊,应该是只有我这种弱鸡)就不得不对每一个结点统计子树,显然复杂度 O(n2)
那么Dsu on tree 就是为了优化这种情况而出现的
为什么会有重复计数呢?这可能是因为我们要计数的最终答案会因为计数结果而发生改变,因此对于子树不同的结点很难用同一个存储容器进行计数
现在有两个结点: U 和 V ,U 是 V 的父结点
那么 V 的计数结果,最终也会被包含到 U 的计数结果里(U 计数的时候会覆盖 V 以及 V 的子树)
联系暴力的流程:我们需要在计数之后,清除当前这棵子树的计数(因为全程用的都是同一个容器(数组))
那么我们记完 V 回溯到 U 的时候,就没必要清除 V 子树的计数了,以此减小复杂度
所以每次都保留重儿子(其子树结点数量最大的子结点)的计数,清除轻儿子的计数
联系树链剖分的相关结论,我们可以精确地得知这么做所能带来的复杂度上的优化程度
以上就是DSU on Tree 的本质了
那么我们拔高一个层次
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 树上启发式合并,或称树上并查集(垃圾翻译我还是喜欢树上启发式) 2 启发式合并,即通过将较小的对象合并至较大的对象以减小复杂度(个人理解) 3 在以上讨论中,启发式合并具体体现为将轻儿子的信息合并至没有消除影响的重儿子上
本文主要为对DSU的个人理解 :)
Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #define maxn 1000000 5 #define LL long long 6 using namespace std; 7 8 vector<int> G[maxn]; 9 10 int TIM,mx,n,L[maxn],R[maxn],son[maxn],sz[maxn],line[maxn*3],cnt[maxn],color[maxn]; 11 LL result[maxn],ans[maxn]; 12 13 void dfs(int u,int fa){ 14 // printf("Now in #%d ",u); 15 sz[u] = 1; L[u] = ++TIM; line[TIM] = color[u]; 16 for(int i = 0;i < G[u].size();i++){ 17 if(G[u][i] == fa) continue; 18 int v = G[u][i]; 19 dfs(v,u); 20 sz[u] += sz[v]; 21 if(!son[u]||sz[v]>sz[son[u]]) 22 son[u] = v; 23 }R[u] = TIM; 24 } 25 26 void Add(int u,int &mx){ 27 for(int i = L[u];i <= R[u];i++){ 28 result[cnt[line[i]]] -= line[i]; 29 cnt[line[i]]++; 30 result[cnt[line[i]]] += line[i]; 31 mx = max(cnt[line[i]],mx); 32 } 33 } 34 35 void Del(int u){ 36 for(int i = L[u];i <= R[u];i++){ 37 result[cnt[line[i]]] -= line[i]; 38 cnt[line[i]]--; 39 result[cnt[line[i]]] += line[i]; 40 } 41 } 42 43 /*void Add(int x,int &mx){ 44 for(int i=L[x];i<=R[x];++i){ 45 result[++cnt[line[i]]]+=color[line[i]]; 46 max(mx,cnt[line[i]]); 47 } 48 } 49 50 void Del(int x,int &mx){ 51 for(int i=L[x];i<=R[x];++i){ 52 if(cnt[color[line[i]]]==mx)--mx; 53 result[cnt[color[line[i]]]--]-=color[line[i]]; 54 } 55 }*/ 56 57 // 10 9 3 4 58 void dsu(int u,int fa){ 59 // printf("Now in #%d son[%d]: %d ",u,u,son[u]); 60 mx = 0; 61 for(int i = 0;i < G[u].size();i++){ 62 if(G[u][i] == fa || G[u][i] == son[u]) continue; 63 dsu(G[u][i],u); 64 // Add(G[u][i],mx); 65 Del(G[u][i]); 66 67 // cout << "Now A" << endl; 68 // printf("#%d color_cnt: ",u); for(int l = 1;l <= 4;l++) printf("%d ",cnt[l]); cout << endl; 69 // printf("#%d color_res: ",u); for(int l = 0;l <= mx;l++) printf("%d ",result[l]); cout << endl; 70 // printf("#%d mx: %d ",u,mx); 71 72 }if(son[u]) dsu(son[u],u); 73 for(int i = 0;i < G[u].size();i++){ 74 if(G[u][i] == fa || G[u][i] == son[u]) continue; 75 Add(G[u][i],mx); 76 } 77 // cout << "Now B" << endl; 78 // printf("#%d color_cnt: ",u); for(int i = 1;i <= 4;i++) printf("%d ",cnt[i]); cout << endl; 79 // printf("#%d color_res: ",u); for(int i = 0;i <= mx;i++) printf("%d ",result[i]); cout << endl; 80 // printf("#%d mx: %d ",u,mx); 81 result[cnt[color[u]]] -= color[u]; 82 cnt[color[u]]++; 83 result[cnt[color[u]]] += color[u]; 84 85 mx = max(cnt[color[u]],mx); 86 while(!result[mx] && mx) mx--; // 这一句加与不加都能AC,但我还是加上去= =保险起见,如果有人研究出原因请告诉我呀qwq 87 ans[u] = max(result[mx],0LL); 88 // cout << "Now C" << endl; 89 // printf("#%d color_cnt: ",u); for(int i = 1;i <= n;i++) printf("%d ",cnt[i]); cout << endl; 90 // printf("#%d color_res: ",u); for(int i = 0;i <= n;i++) printf("%d ",result[i]); cout << endl; 91 // printf("#%d mx: %d ",u,mx); 92 } 93 94 int main(){ 95 96 // freopen("1.in","r",stdin); 97 98 scanf("%d",&n); 99 100 for(int i = 1;i <= n;i++) 101 scanf("%d",&color[i]); 102 103 for(int i = 1;i < n;i++){ 104 int u,v; scanf("%d%d",&u,&v); 105 G[u].push_back(v); G[v].push_back(u); 106 } 107 108 dfs(1,1); 109 110 // for(int i = 1;i <= n;i++) printf("#%d: %d ~ %d ",i,L[i],R[i]); 111 112 dsu(1,1); 113 114 for(int i = 1;i <= n;i++) if(i == 1) printf("%I64d",ans[i]); else printf("% I64d",ans[i]); 115 116 return 0; 117 }