题目链接

单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和。反过来思考只需要求有多少条路径没有经过这种颜色即可。

具体实现过程比较复杂,很神奇的一个树形dp,下面给出一个含较详细注释的代码及对应的一组自造的数据以及图片来进行解释

欢迎交流,给出意见~~~

数据

  1. /*
    第二行的1 2 3在图中分别用红黄蓝来表示
  2. 15
  3. 1 2 3 1 2 3 1 2 3 1 2 3 1 2 3
  4. 1 2
  5. 1 3
  6. 2 4
  7. 2 5
  8. 3 6
  9. 3 7
  10. 4 8
  11. 4 9
  12. 5 10
  13. 5 11
  14. 6 12
  15. 6 13
  16. 7 14
  17. 7 15
  18. */

含注释的代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4.  
  5. const int N=2e5+;
  6. int n;
  7. int c[N]; //各结点的颜色
  8. int size[N]; //size[i]记录结点i的子树的大小,叶子为1
  9. int vis[N]; //vis[i]记录颜色i是否出现过
  10. int sum[N]; //见函数内注释及图片
  11. vector<int> adj[N];
  12. LL ans,de;
  13.  
  14. LL C(LL a,LL b) //计算组合数,这样写是为了增加后面的代码的可读性
  15. {
  16. LL ret=;
  17. for(int i=;i<=b;i++)
  18. ret=ret*(a+-i)/i;
  19. return ret;
  20. }
  21.  
  22. void dfs(int u,int pre)
  23. {
  24. // 定义 u 为“当前结点”
  25. // sum[c[u]]表示, 整棵树中,已经被dfs过的,
  26. // 与当前结点具有相同颜色的结点的所有子树的大小之和
  27. // 不重复计数
  28. // 图一展示了的是刚刚进入dfs(7,3)时sum[c[u]]包含的结点
  29. printf("\n\n==================================\nEnter->%d\n\n",u);
  30. int all=;
  31. size[u]=;
  32. for(int to:adj[u])
  33. {
  34. if(to==pre) continue;
  35. int sumu_bd=sum[c[u]]; //bd : before dfs
  36. //记录此次dfs前的sum[c[u]]
  37. dfs(to,u);
  38. size[u]+=size[to];
  39. int part=sum[c[u]]-sumu_bd; //dfs过后,sum[c[u]]会产生一个增量,用part来记录这个增量
  40. all+=part; //all用来记录,对u dfs的过程中,sum[c[u]]产生的总增量
  41. //这是在为 u返回pre时更新sum[c[u]]做准备
  42. printf("from %d return to %d\n",to,u);
  43. printf("all=%d,sumu_bd=%d,part=%d,sum[c[u]]=%d\n",all,sumu_bd,part,sum[c[u]]);
  44. printf("to=%d,size[to]=%d\n",to,size[to]);
  45. de+=C(size[to]-part,); //size[to]-part的含义: 在to为根节点的子树中,有一部分结点与to位于同一“块”,
  46. // 这个块以 与u颜色相同的结点(不含),或是叶子(含,若叶子与u颜色相同则不含) 为边界
  47. // size[to]-part表示的是这个块的大小
  48. // 图二展示了 dfs(1,0)内,刚刚执行完dfs(2,1)后,更新de时的size[2]-part
  49. printf("\nnow,de=%d\n\n",de);
  50. }
  51. printf("\n\n=== leaving... ===\n\n");
  52. printf("pre_sum[c[u]]=%d\n",sum[c[u]]);
  53. sum[c[u]]+=size[u]-all;
  54. printf("after_sum[c[u]]=%d\n",sum[c[u]]);
  55. printf("\nleave from %d\n\n==================================\n\n",u);
  56. }
  57.  
  58. int main()
  59. {
  60. int kase=;
  61. while(~scanf("%d",&n))
  62. {
  63. memset(vis,,sizeof(vis));
  64. memset(size,,sizeof(size));
  65. memset(sum,,sizeof(sum));
  66. for(int i=;i<=n;i++) adj[i].clear();
  67. int c_num=;
  68. de=;
  69. for(int i=;i<=n;i++)
  70. {
  71. scanf("%d",&c[i]);
  72. if(!vis[c[i]]) c_num++;
  73. vis[c[i]]=;
  74. }
  75. for(int i=;i<n;i++)
  76. {
  77. int u,v;
  78. scanf("%d%d",&u,&v);
  79. adj[u].push_back(v);
  80. adj[v].push_back(u);
  81. }
  82. dfs(,);
  83. for(int i=;i<=n;i++)
  84. if(i!=c[]&&vis[i]) de+=C(n-sum[i],);
  85. ans=C(n,)*c_num-de;
  86. printf("Case #%d: %lld\n",++kase,ans);
  87. }
  88. }

图一:

图二:

AC代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long LL;
  4.  
  5. const int N=2e5+;
  6. int n;
  7. int c[N];
  8. int size[N];
  9. int vis[N];
  10. int sum[N];
  11. vector<int> adj[N];
  12. LL ans,de;
  13.  
  14. LL C(LL a,LL b)
  15. {
  16. LL ret=;
  17. for(int i=;i<=b;i++)
  18. ret=ret*(a+-i)/i;
  19. return ret;
  20. }
  21.  
  22. void dfs(int u,int pre)
  23. {
  24. int all=;
  25. size[u]=;
  26. for(int to:adj[u])
  27. {
  28. if(to==pre) continue;
  29. int sumu_bd=sum[c[u]];
  30. dfs(to,u);
  31. size[u]+=size[to];
  32. int part=sum[c[u]]-sumu_bd;
  33. all+=part;
  34. de+=C(size[to]-part,);
  35. }
  36. sum[c[u]]+=size[u]-all;
  37. }
  38.  
  39. int main()
  40. {
  41. int kase=;
  42. while(~scanf("%d",&n))
  43. {
  44. memset(vis,,sizeof(vis));
  45. memset(size,,sizeof(size));
  46. memset(sum,,sizeof(sum));
  47. for(int i=;i<=n;i++) adj[i].clear();
  48. int c_num=;
  49. de=;
  50. for(int i=;i<=n;i++)
  51. {
  52. scanf("%d",&c[i]);
  53. if(!vis[c[i]]) c_num++;
  54. vis[c[i]]=;
  55. }
  56. for(int i=;i<n;i++)
  57. {
  58. int u,v;
  59. scanf("%d%d",&u,&v);
  60. adj[u].push_back(v);
  61. adj[v].push_back(u);
  62. }
  63. dfs(,);
  64. for(int i=;i<=n;i++)
  65. if(i!=c[]&&vis[i]) de+=C(n-sum[i],);
  66. ans=C(n,)*c_num-de;
  67. printf("Case #%d: %lld\n",++kase,ans);
  68. }
  69. }

简版的

hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】的更多相关文章

  1. HDU 6035 - Colorful Tree | 2017 Multi-University Training Contest 1

    /* HDU 6035 - Colorful Tree [ DFS,分块 ] 题意: n个节点的树,每个节点有一种颜色(1~n),一条路径的权值是这条路上不同的颜色的数量,问所有路径(n*(n-1)/ ...

  2. hdu 6044 : Limited Permutation (2017 多校第一场 1012) 【输入挂 组合数学】

    题目链接 参考博客: http://blog.csdn.net/jinglinxiao/article/details/76165353 http://blog.csdn.net/qq_3175920 ...

  3. hdu 6047: Maximum Sequence (2017 多校第二场 1003)【贪心】

    题目链接 可以贪心写,先把b数组按从小到大的顺序排个序,根据b[i]的值来产生a[n+i] 借助一个c数组,c[i]记录,j从i到n,a[j]-j的最大值,再加上一个实时更新的变量ma,记录从n+1到 ...

  4. 2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】

    Colorful Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  5. 2017ACM暑期多校联合训练 - Team 1 1003 HDU 6035 Colorful Tree (dfs)

    题目链接 Problem Description There is a tree with n nodes, each of which has a type of color represented ...

  6. HDU-6035 Colorful Tree(树形DP) 2017多校第一场

    题意:给出一棵树,树上的每个节点都有一个颜色,定义一种值为两点之间路径中不同颜色的个数,然后一棵树有n*(n-1)/2条 路径,求所有的路径的值加起来是多少. 思路:比赛的时候感觉是树形DP,但是脑袋 ...

  7. HDU 6035 Colorful Tree(补集思想+树形DP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6035 [题目大意] 给出一颗树,一条路径的价值为其上点权的种类数,求路径总价值 [题解] 单独考虑 ...

  8. HDU 6035 Colorful Tree (树形DP)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6035 [题目大意] 给出一颗树,一条路径的价值为其上点权的种类数,求路径总价值 [题解] 我们计算 ...

  9. HDU 6035 Colorful Tree(dfs)

    题意:一棵有n个点的树,树上每个点都有颜色c[i],定义每条路径的值为这条路径上经过的不同颜色数量和.求所有路径的值的和. 可以把问题转化为对每种颜色有多少条不同的路径至少经过这种颜色的点,然后加和. ...

随机推荐

  1. VUE Right-hand side of ‘instanceof’ is not an object 解决方案

    这里要注意一下, props之前没注意写成了   props: {     wrd: '',       sname:'zs'   },   这样是不能被解析成object的,所以一定要写的更具体一点 ...

  2. Delphi XE2 之 FireMonkey 入门(13) - 动画(下)

    TAnimation 类的主要成员: protected   function NormalizedTime: Single;      //   procedure ProcessAnimation ...

  3. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_07 缓冲流_5_BufferedWriter_字符缓冲输出流

    使用newLine来换行 同样的效果 println的源码里面其实就用的就是newLine()

  4. python+selenium元素定位——8种方法

    定位元素,selenium提供了8中元素定位方法: (1)find_element_by_id() :html规定,id在html中必须是唯一的,有点类似于身份证号 (2)find_element_b ...

  5. OuterXml和InnerXml(2)

    官方例子:https://msdn.microsoft.com/en-us/library/system.xml.xmlnode.outerxml.aspx using System; using S ...

  6. oracle--约束(主键、非空、检查)

    问题1:学号重复了,数据还可以插入成功 使用主键约束:学号是唯一标识一条数据的,所以必须唯一且不能为空 ---(1).在确定为主键的字段后添加 primary key关键字 ---(2).在创建表的后 ...

  7. 使用Redis共享用户登录成功的信息

    一.问题 比如CSDN,开源中国等等网站,用户登录后不一定什么时候就会把你T了,意思就是不一定哪天在打开网站的时候就让你重新登录.这是怎么回事呢? 再比如:如果存到将用户信息存到Redis了,不清除的 ...

  8. Vue源码详细解析:transclude,compile,link,依赖,批处理...一网打尽,全解析!

    用了Vue很久了,最近决定系统性的看看Vue的源码,相信看源码的同学不在少数,但是看的时候却发现挺有难度,Vue虽然足够精简,但是怎么说现在也有10k行的代码量了,深入进去逐行查看的时候感觉内容庞杂并 ...

  9. TensorFlow 解决“ImportError: Could not find 'cudnn64_6.dll'”

    解决“ImportError: Could not find 'cudnn64_6.dll'” 1. 问题描述 运行一个基于Tensorflow的代码时报错,如下所示: ImportError: Co ...

  10. 三大浏览器(火狐-谷歌-IE浏览器)驱动版本下载

    1.chrome浏览器: 对于chrome浏览器,有时候会有闪退的情况,有时候也许是版本冲突的问题,我们要对照着这个表来对照查看是不是webdriver和chrome版本不对应 点击下载chrome的 ...