本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

题目链接:codeforces600E

解法一:$O(nlog^2n)$

正解:启发式合并

解题报告:

  这道题求的是每个点的子树内的出现次数最大的数字的和。

  考虑启发式合并,我用$col[x]$的$map$表示$x$的子树内的每种权值的出现次数,$sum[x]$的$map$表示$x$的子树内每种出现次数的权值和。

  那么我在将儿子节点和父亲节点合并的时候只需要根据$col$的$size$,把小的往大的里面暴力合并就可以了。

  $get$了$map$的正确姿势…

  1. //It is made by ljh2000
  2. //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
  3. #include <iostream>
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <cstdio>
  7. #include <cmath>
  8. #include <algorithm>
  9. #include <ctime>
  10. #include <vector>
  11. #include <queue>
  12. #include <map>
  13. #include <set>
  14. #include <string>
  15. #include <complex>
  16. #include <bitset>
  17. using namespace std;
  18. typedef long long LL;
  19. typedef long double LB;
  20. const double pi = acos(-1);
  21. const int MAXN = 100011;
  22. const int MAXM = 200011;
  23. int n,a[MAXN],ecnt,first[MAXN],to[MAXM],next[MAXM];
  24. LL ans[MAXN];
  25. map<int,int>col[MAXN];//统计每种颜色的出现次数
  26. map<int,LL>sum[MAXN];//统计每种出现次数的sum
  27. inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
  28. inline int getint(){
  29. int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
  30. if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
  31. }
  32.  
  33. inline void dfs(int x,int fa){
  34. col[x][a[x]]=1;
  35. sum[x][1]=a[x];
  36. int now,cc;
  37. for(int i=first[x];i;i=next[i]) {
  38. int v=to[i]; if(v==fa) continue;
  39. dfs(v,x);
  40. if(col[x].size()<col[v].size()) swap(col[x],col[v]),swap(sum[x],sum[v]);//小的往大的上面合并!!!
  41. for(map<int,int>::iterator it=col[v].begin();it!=col[v].end();it++) {
  42. now=it->first; cc=it->second;
  43. if(col[x].count(now)>0) {
  44. sum[x][col[x][now]]-=now;
  45. col[x][now]+=cc;
  46. sum[x][col[x][now]]+=now;
  47. }
  48. else col[x][now]=col[v][now],sum[x][col[x][now]]+=now;
  49. }
  50. }
  51. map<int,LL>::iterator it=sum[x].end();
  52. it--;//最大的应该是end-1,end是一个空指针...
  53. ans[x]=it->second;
  54. }
  55.  
  56. inline void work(){
  57. n=getint(); for(int i=1;i<=n;i++) a[i]=getint(); int x,y;
  58. for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); }
  59. dfs(1,0);
  60. for(int i=1;i<=n;i++)
  61. printf("%I64d ",ans[i]);
  62. }
  63.  
  64. int main()
  65. {
  66. work();
  67. return 0;
  68. }
  69. //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

解法二:$O(nlogn)$

正解:$dsu$ $on$ $tree$

解题报告:

  学了一发$dsu$ $on$ $tree$。

  这个算法主要处理的是对于树上某一特征的不带修改子树统计问题,通常可以做到$O(nlogn)$。

  大概做法就是先链剖,然后我考虑用一个全局数组$cnt$来表示某个值的出现次数,如果是暴力的做法的话,就是每次处理一个节点时暴力把整棵子树的贡献加入,同时更新答案,做完之后暴力把整棵子树的贡献消除,递归做儿子节点。

  而$dsu$ $on$ $tree$的做法就是,每次先递归处理完轻儿子,然后再做重儿子。

  到了统计答案的时候,同样是把贡献暴力加入,但是假如这个点是他的父亲节点的重儿子,那么不消除贡献(所以加入贡献的时候注意不要加到重儿子上去了),往上走,直到某个点是父亲的轻儿子再把整棵子树的贡献消除即可。

  1. //It is made by ljh2000
  2. //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
  3. #include <iostream>
  4. #include <cstdlib>
  5. #include <cstring>
  6. #include <cstdio>
  7. #include <cmath>
  8. #include <algorithm>
  9. #include <ctime>
  10. #include <vector>
  11. #include <queue>
  12. #include <map>
  13. #include <set>
  14. #include <string>
  15. #include <complex>
  16. #include <bitset>
  17. using namespace std;
  18. typedef long long LL;
  19. typedef long double LB;
  20. typedef complex<double> C;
  21. const double pi = acos(-1);
  22. const int MAXN = 100011;
  23. const int MAXM = 200011;
  24. int n,a[MAXN],cnt[MAXN],ecnt,first[MAXN],to[MAXM],next[MAXM],size[MAXN],son[MAXN],Son;
  25. LL sum,Max,ans[MAXN];
  26. inline void link(int x,int y){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; }
  27. inline int getint(){
  28. int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
  29. if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
  30. }
  31.  
  32. inline void dfs(int x,int fa){
  33. size[x]=1;
  34. for(int i=first[x];i;i=next[i]) {
  35. int v=to[i]; if(v==fa) continue;
  36. dfs(v,x); size[x]+=size[v];
  37. if(size[v]>size[son[x]]) son[x]=v;
  38. }
  39. }
  40.  
  41. inline void add(int x,int fa,int val){
  42. cnt[ a[x] ]+=val;
  43. if(cnt[ a[x] ]>Max) Max=cnt[ a[x] ],sum=a[x];
  44. else if(cnt[ a[x] ]==Max) sum+=a[x];
  45. for(int i=first[x];i;i=next[i]) {
  46. int v=to[i]; if(v==fa || v==Son) continue;
  47. add(v,x,val);
  48. }
  49. }
  50.  
  51. inline void solve(int x,int fa,bool T){
  52. for(int i=first[x];i;i=next[i]) {
  53. int v=to[i]; if(v==fa || v==son[x]) continue;
  54. solve(v,x,1);
  55. }
  56.  
  57. if(son[x])
  58. solve(son[x],x,0),Son=son[x];
  59.  
  60. add(x,fa,1); Son=0;
  61. ans[x]=sum;
  62.  
  63. if(T==1)
  64. add(x,fa,-1),sum=Max=0;
  65. }
  66.  
  67. inline void work(){
  68. n=getint(); for(int i=1;i<=n;i++) a[i]=getint();
  69. int x,y; for(int i=1;i<n;i++) { x=getint(); y=getint(); link(x,y); link(y,x); }
  70. dfs(1,0);
  71. solve(1,0,1);
  72. for(int i=1;i<=n;i++)
  73. printf("%I64d ",ans[i]);
  74. }
  75.  
  76. int main()
  77. {
  78. work();
  79. return 0;
  80. }
  81. //有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。

  

codeforces600E Lomsat gelral的更多相关文章

  1. [Codeforces600E] Lomsat gelral(树上启发式合并)

    [Codeforces600E] Lomsat gelral(树上启发式合并) 题面 给出一棵N个点的树,求其所有子树内出现次数最多的颜色编号和.如果多种颜色出现次数相同,那么编号都要算进答案 N≤1 ...

  2. CodeForces600E Lomsat gelral 线段树合并

    从树上启发式合并搜出来的题 然而看着好像线段树合并就能解决??? 那么就用线段树合并解决吧 维护\(max, sum\)表示值域区间中的一个数出现次数的最大值以及所有众数的和即可 复杂度\(O(n \ ...

  3. codeforces600E. Lomsat gelral(dsu on tree)

    dsu on tree先分轻重儿子先处理轻边,再处理重儿子再加上轻儿子的答案 #include<iostream> #include<cstdio> #include<q ...

  4. codeforces600E Lomsat gelral【线段树合并/DSU】

    第一次AC这道题,是三年前的一个下午,也许晚上也说不定.当时使用的\(DSU\) \(on\) \(tree\)算法,如今已经淡忘,再学习新的算法过程中,却与旧物重逢.生活中充满不可知会的相遇,即使重 ...

  5. Educational Codeforces Round 2 E. Lomsat gelral 启发式合并map

    E. Lomsat gelral Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/600/prob ...

  6. Codeforces 600 E - Lomsat gelral

    E - Lomsat gelral 思路1: 树上启发式合并 代码: #include<bits/stdc++.h> using namespace std; #define fi fir ...

  7. 【CF600E】 Lomsat gelral

    CF600E Lomsat gelral Solution 考虑一下子树的问题,我们可以把一棵树的dfn序搞出来,那么子树就是序列上的一段连续的区间. 然后就可以莫队飞速求解了. 但是这题还有\(\T ...

  8. 【CodeForces】600 E. Lomsat gelral (dsu on tree)

    [题目]E. Lomsat gelral [题意]给定n个点的树,1为根,每个点有一种颜色ci,一种颜色占领一棵子树当且仅当子树内没有颜色的出现次数超过它,求n个答案——每棵子树的占领颜色的编号和Σc ...

  9. 【CF600E】Lomsat gelral(dsu on tree)

    [CF600E]Lomsat gelral(dsu on tree) 题面 洛谷 CF题面自己去找找吧. 题解 \(dsu\ on\ tree\)板子题 其实就是做子树询问的一个较快的方法. 对于子树 ...

随机推荐

  1. point in polygon algorithm

    Point-In-Polygon Algorithm — Determining Whether A Point Is Inside A Complex Polygon © 1998,2006,200 ...

  2. 001-linux scp文件拷贝

    scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的.可能会稍微影响一下速度.当你服务器 ...

  3. 页面优化——减少HTTP请求数

    1.关于减少http请求数 关于减少http请求数,是前端开发性能优化的一个非常重要方面,所以在基本所有的优化原则里,都有这一条原则:减少http请求数. 先不考虑其他的,我们先考虑为什么减少http ...

  4. SQL Server扩展属性的增、删、改、查

    使用 sql 语句创建表时,可以使用系统存储过程 sp_addextendedproperty 给字段添加描述说明. sp_addextendedproperty 语法: sp_addextended ...

  5. ruby中的可调用对象--方法

    上一篇讲了ruby中的可调用对象proc和lambda,他们都是块转换成的对象.ruby中的可调用对象还有方法.通过使用method方法,并且以方法名作为参数(字符串或者符号),就可以得到一个方法对象 ...

  6. AtCoder Regular Contest 080 D - Grid Coloring

    地址:http://arc080.contest.atcoder.jp/tasks/arc080_b 题目: D - Grid Coloring Time limit : 2sec / Memory ...

  7. hdp (ambari) 集成hue

    ambari-server resetambari-admin-password-reset https://github.com/EsharEditor/ambari-hue-service可以基于 ...

  8. selenium+python—实现自动化测试基本思路

    测试是一个贯穿于整个开发过程的连续过程,测试最基本的原理就是比较预期结果是否与实际执行结果相同,如果相同则测试成功,否则测试失败. 为了让单元测试代码能够被测试和维护人员更容易地理解,最好的解决办法是 ...

  9. python3_Logging模块详解

    python的logging模块提供了通用的日志系统,可以方便第三方模块或应用使用. 简单使用 import logging # logging.config.fileConfig("./l ...

  10. SpringMvc接受特殊符号参数被转义

    WEB开发时,在前端通过get / post 方法传递参数的时候  如果实参附带特殊符号,后端接收到的值中特殊符号就会被转义 例如该请求: http://localhost:10001/demo/in ...