【转】HDU-6035-Colorful Tree
转自http://blog.csdn.net/Bahuia/article/details/76141574
题意:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035
一棵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的高度最高一批结点为根的子树大小总和。
代码:

1 #include <bits/stdc++.h>
2 using namespace std;
3 const int MAXN = 2e5 + 10;
4 typedef long long LL;
5
6 //题解地址
7 //http://blog.csdn.net/Bahuia/article/details/76141574
8 LL color[MAXN], sz[MAXN], sum[MAXN], vis[MAXN]; //sum[i]记录的是到达当前节点时,颜色为i的高度最高一批结点为根的子树大小总和
9 //sz:全部节点数
10 vector <int> tree[MAXN];
11 LL ans;
12
13 LL dfs(int u, int pa) {
14 sz[u] = 1;
15 LL allson = 0;
16 int cnt = tree[u].size();
17 for (int i = 0; i < cnt; i++) {
18 int v = tree[u][i];
19 if (v == pa) continue;
20 LL last = sum[color[u]]; // 保存递归之前的sum值
21 sz[u] += dfs(v, u);
22 LL add = sum[color[u]] - last; // add就是结点v为根的子树中颜色为color[u]且高度最高的若干子树的大小
23 // 对于结点v来说,sz[v]-add就是v这棵子树最上端的,且不包含颜色为color[u]的连通块大小
24 ans += (sz[v] - add) * (sz[v] - add - 1) / 2; // 对这个连通块中任意两个点的路径都不包含颜色color[u]
25 allson += sz[v] - add; // allson记录下儿子结点v组成的不含颜色color[u]的连通块大小总和
26 }
27 sum[color[u]] += allson + 1; // sum更新,此时要加上不含color[u]连通块的大小总和以及u自己
28 return sz[u];
29 }
30
31 int main() {
32 //freopen("data2.in", "r", stdin);
33 int n, cs = 0;
34 while (scanf("%d", &n) !=EOF) {
35 memset(vis, 0, sizeof(vis));
36 memset(sum, 0, sizeof(sum));
37 int cnt = 0;
38 for (int i = 1; i <= n; i++) {
39 scanf("%I64d", &color[i]);
40 if (!vis[color[i]]) ++cnt;
41 vis[color[i]] = 1;
42 tree[i].clear();
43 }
44 for (int i = 1; i < n; i++) {
45 int u, v;
46 scanf("%d%d", &u, &v);
47 tree[u].push_back(v);
48 tree[v].push_back(u);
49 }
50 printf("Case #%d: ", ++cs);
51 if (cnt == 1) { // 只有一种颜色的特殊情况
52 printf("%I64d\n", (LL)n * (n - 1LL) / 2LL);
53 continue;
54 }
55 ans = 0;
56 dfs(1, -1);
57 for (int i = 1; i <= n; i++) { // 注意最后要对整棵树来补充所有颜色剩下的联通块
58 if (!vis[i]) continue;
59 else {
60 ans += (n - sum[i]) * (n - sum[i] - 1LL) / 2LL;//子树下的统计完了,然后统计非子树的
61 }
62 }
63 printf("%I64d\n", (LL)n * (n - 1LL) / 2LL * cnt - ans);
64 }
65 return 0;
66 }
【转】HDU-6035-Colorful Tree的更多相关文章
- HDU 6035 - Colorful Tree | 2017 Multi-University Training Contest 1
/* HDU 6035 - Colorful Tree [ DFS,分块 ] 题意: n个节点的树,每个节点有一种颜色(1~n),一条路径的权值是这条路上不同的颜色的数量,问所有路径(n*(n-1)/ ...
- 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 ...
- HDU 6035 Colorful Tree(补集思想+树形DP)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6035 [题目大意] 给出一颗树,一条路径的价值为其上点权的种类数,求路径总价值 [题解] 单独考虑 ...
- HDU 6035 Colorful Tree (树形DP)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6035 [题目大意] 给出一颗树,一条路径的价值为其上点权的种类数,求路径总价值 [题解] 我们计算 ...
- 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 ...
- HDU 6035 Colorful Tree(dfs)
题意:一棵有n个点的树,树上每个点都有颜色c[i],定义每条路径的值为这条路径上经过的不同颜色数量和.求所有路径的值的和. 可以把问题转化为对每种颜色有多少条不同的路径至少经过这种颜色的点,然后加和. ...
- hdu 6035:Colorful Tree (2017 多校第一场 1003) 【树形dp】
题目链接 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可. 具体实现过程比较复杂,很神奇的一个树形dp,下面给出一个含较详细 ...
- hdu 6035 Colorful Tree(虚树)
考虑到树上操作:首先题目要我们求每条路径上出现不同颜色的数量,并把所有加起来得到答案:我们知道俩俩点之间会形成一条路径,所以我们可以知道每个样例的总的路径的数目为:n*(n-1)/2: 这样单单的求, ...
- HDU 5574 Colorful Tree
• 给出一棵树,每个点有初始的颜色,支持两种操作• 将一个点的子树染成一种给定颜色• 问一个点的子树里有几种不同的颜色 •
- HDU 6035 (虚树)(统计颜色)
HDU 6035 Colorful Tree Problem : 给一棵树,每个结点有一种颜色,定义每条路径的权值为这条路径上颜色的种数,询问所有路径(C(n,2)条)的权值之和. Solution ...
随机推荐
- CodeFoeces GYM 101466A Gaby And Addition (字典树)
gym 101466A Gaby And Addition 题目分析 题意: 给出n个数,找任意两个数 “相加”,求这个结果的最大值和最小值,注意此处的加法为不进位加法. 思路: 由于给出的数最多有 ...
- # Pycharm打造高效Python IDE
Pycharm打造高效Python IDE 建议以scientific mode运行,在科学计算时,可以方便追踪变量变化,并且会提示函数的用法,比普通模式下的提示更加智能,一般在文件中引入了numpy ...
- bash脚本测试总结
bash脚本测试总结 跟踪脚本的执行 可以让bash打印出你脚本执行的过程中的所有语句.这很简单,只需要使用bash的-x选项就可以做到,下面让我们来看一下. 下面的这段脚本,先是输出一个问候 ...
- python发起post请求获取json数据使用requests方法
最普通的答案 我一直就觉得GET和POST没有什么除了语义之外的区别,自打我开始学习Web编程开始就是这么理解的 . 可能很多人都已经猜到了答案是: 1.GET 使用URL或Cookie传参.而POS ...
- luogu P3620 [APIO/CTSC 2007]数据备份
luogu 首先如果一条线不是了连接的相邻两个位置一定不优,把它拆成若干连接相邻位置的线.所以现在问题是有\(n\)个物品,选\(k\)个,要求选的位置不能相邻,求最小总和 如果没有选的位置不能相邻这 ...
- loj 6031「雅礼集训 2017 Day1」字符串
loj 注意到每次询问串长度都是给定的,并且询问串长\(k*\)询问次数\(q<10^5\),所以这里面一个东西大的时候另一个东西就小,那么考虑对较小的下功夫 如果\(k\le \sqrt{n} ...
- Vue之动态class写法总结
对象方法 最简单的绑定 :class="{ 'active': isActive }" 判断是否绑定一个active :class="{'active':isActive ...
- jq上滑加载更多
html 结构 <div id="main"> <ul class="order-list" id="list_box"& ...
- git解决pre-commit hook failed的问题
最近在提交前端代码的时候发现提交不上去,一直报错 一.错误详情 二.错误分析 1.刚开始用vsCode提交,后更改为命令提交,依旧报错: 2.经过查询资料,发现是pre-commit钩子的原因. ...
- linux shell 数组的使用
引言 在Linux平台上工作,我们经常需要使用shell来编写一些有用.有意义的脚本程序.有时,会经常使用shell数组.那么,shell中的数组是怎么表现的呢,又是怎么定义的呢?接下来逐一的进行讲解 ...