博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】
阅读量:5723 次
发布时间:2019-06-18

本文共 3038 字,大约阅读时间需要 10 分钟。

Colorful Tree

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 1539    Accepted Submission(s): 616

Sample Input
31 2 11 22 361 2 1 3 2 11 21 32 42 53 6

 

Sample Output
Case #1: 6Case #2: 29

 

Source
题目链接:

题意: 

一棵n个结点的树,每个结点都有颜色,定义两点之间的路径长度为路径上出现的不同颜色数目,求树上所有路径的长度和。


思路:

“真的难”系列。

官方题解:

首先这题肯定是算贡献,也就是计算出每种颜色参与了多少条路径,但这样正面考虑并不容易,不妨从反面考虑,计算每种颜色没有参与多少路径,然后拿 (路径总数 * 颜色总数) - 没参与的贡献,就是答案了。
对于一种颜色x,怎么计算没参与的路径数目呢,很显然,对于每个不包含颜色x的连通块中任意两点路径都是x不参与的贡献,那么问题就转化为,对于任意一种颜色x,需要求出每个不包含x的连通块大小。
这里利用了树形dp,对于结点u,若u的颜色为x,那么dfs(u)的过程中,我们就想知道对于u的每个儿子v构成的子树中最高的一批颜色也为x的结点是哪些,要是知道这些结点子树的大小,只要拿子树v的大小减去这些节点子树的大小,就可以得到包括v在内的没有颜色x的连通块大小。
举个例子,如图:

对于结点1,我们想求出与1相邻的且不是黑色的结点组成的连通块大小,此时就要dfs结点1的两个儿子2和3,若我们处理出来结点2中,最高的一批黑色结点(4,8)的所构成子树的大小分别为2和1,那么我们拿2为根子树的大小5,减去2,减去1,就得到了结点2不包含黑色结点的连通块大小是5-2-1=2,也就是图中的2和5组成的连通块。同理对3,可以求得连通块大小是2({3,6})。

计算出了子树u中连通块大小对答案的贡献之后,就要将当前最高一批的黑色结点更新为u,最高黑色节点构成的子树大小sum加上子树u中没有计算的那部分大小5({1,2,3,5,6})。
具体实现,看代码,sum[x]表示的遍历到当前位置,颜色为x的高度最高一批结点为根的子树大小总和。

下面给出AC代码:

 

1 #include 
2 using namespace std; 3 const int MAXN = 2e5 + 10; 4 typedef long long LL; 5 6 LL color[MAXN], sz[MAXN], sum[MAXN], vis[MAXN]; 7 vector
tree[MAXN]; 8 LL ans; 9 10 LL dfs(int u, int pa) {11 sz[u] = 1;12 LL allson = 0;13 int cnt = tree[u].size();14 for (int i = 0; i < cnt; i++) {15 int v = tree[u][i];16 if (v == pa) continue;17 LL last = sum[color[u]]; // 保存递归之前的sum值18 sz[u] += dfs(v, u);19 LL add = sum[color[u]] - last; // add就是结点v为根的子树中颜色为color[u]且高度最高的若干子树的大小20 // 对于结点v来说,sz[v]-add就是v这棵子树最上端的,且不包含颜色为color[u]的连通块大小21 ans += (sz[v] - add) * (sz[v] - add - 1) / 2; // 对这个连通块中任意两个点的路径都不包含颜色color[u]22 allson += sz[v] - add; // allson记录下儿子结点v组成的不含颜色color[u]的连通块大小总和23 }24 sum[color[u]] += allson + 1; // sum更新,此时要加上不含color[u]连通块的大小总和以及u自己25 return sz[u];26 }27 28 int main() {29 //freopen("in.txt", "r", stdin);30 int n, cs = 0;31 while (scanf("%d", &n) !=EOF) {32 memset(vis, 0, sizeof(vis));33 memset(sum, 0, sizeof(sum));34 int cnt = 0;35 for (int i = 1; i <= n; i++) {36 scanf("%I64d", &color[i]);37 if (!vis[color[i]]) ++cnt;38 vis[color[i]] = 1;39 tree[i].clear();40 }41 for (int i = 1; i < n; i++) {42 int u, v;43 scanf("%d%d", &u, &v);44 tree[u].push_back(v);45 tree[v].push_back(u);46 }47 printf("Case #%d: ", ++cs);48 if (cnt == 1) { // 只有一种颜色的特殊情况49 printf("%I64d\n", (LL)n * (n - 1LL) / 2LL);50 continue;51 }52 ans = 0;53 dfs(1, -1);54 for (int i = 1; i <= n; i++) { // 注意最后要对整棵树来补充所有颜色剩下的联通块55 if (!vis[i]) continue;56 ans += (n - sum[i]) * (n - sum[i] - 1LL) / 2LL;57 }58 printf("%I64d\n", (LL)n * (n - 1LL) / 2LL * cnt - ans);59 }60 return 0;61 }

 

 

转载地址:http://ylzwx.baihongyu.com/

你可能感兴趣的文章
Android NFC开发(二)——Android世界里的NFC所具备的条件以及使用方法
查看>>
java 中容易误解的地方
查看>>
使用C写Python的模块
查看>>
六顶思考帽——平行思维方式
查看>>
WCF 序列化与反序列化复杂类型(DataContractSerializer)
查看>>
201608北京云栖大会Workshop - 视频场景下的容器服务实践
查看>>
虚拟机的几种分类
查看>>
dom addeventlistener与id 绑定事件的区别
查看>>
MySQL内核月报 2015.01-MySQL · 新增特性· DDL fast fail
查看>>
【资料整理】VC工程中的各种文件
查看>>
Linux软连接和硬链接
查看>>
Java中不同的并发实现的性能比较
查看>>
[LeetCode]97.Interleaving String
查看>>
ios零基础学习 准备什么,如何去学习
查看>>
Git 如何将branchA的提交同步到BranchB
查看>>
强烈推荐20个必须了解的API,涉及机器学习、NLP和人脸检测
查看>>
Innodb存储引擎
查看>>
url中中文转码
查看>>
history.back();history.go(-1);触发操作后无效解决方案
查看>>
elixir官方教程Mix与OTP(六) 依赖和伞形项目
查看>>