hdu6035树形dp
来源:互联网 发布:人工智能 英文介绍 编辑:程序博客网 时间:2024/05/21 18:21
“真的难”系列。
首先这题肯定是算贡献,也就是计算出每种颜色参与了多少条路径,但这样正面考虑并不容易,不妨从反面考虑,计算每种颜色没有参与多少路径,然后拿 (路径总数 * 颜色总数) - 没参与的贡献,就是答案了。
对于一种颜色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的高度最高一批结点为根的子树大小总和。
#include <bits/stdc++.h>using namespace std;const int MAXN = 2e5 + 10;typedef long long LL;LL color[MAXN], sz[MAXN], sum[MAXN], vis[MAXN];vector <int> tree[MAXN];LL ans;LL dfs(int u, int pa) { sz[u] = 1; LL allson = 0; int cnt = tree[u].size(); for (int i = 0; i < cnt; i++) { int v = tree[u][i]; if (v == pa) continue; LL last = sum[color[u]]; // 保存递归之前的sum值 sz[u] += dfs(v, u); LL add = sum[color[u]] - last; // add就是结点v为根的子树中颜色为color[u]且高度最高的若干子树的大小 // 对于结点v来说,sz[v]-add就是v这棵子树最上端的,且不包含颜色为color[u]的连通块大小 ans += (sz[v] - add) * (sz[v] - add - 1) / 2; // 对这个连通块中任意两个点的路径都不包含颜色color[u] allson += sz[v] - add; // allson记录下儿子结点v组成的不含颜色color[u]的连通块大小总和 } sum[color[u]] += allson + 1; // sum更新,此时要加上不含color[u]连通块的大小总和以及u自己 return sz[u];}int main() { //freopen("in.txt", "r", stdin); int n, cs = 0; while (scanf("%d", &n) !=EOF) { memset(vis, 0, sizeof(vis)); memset(sum, 0, sizeof(sum)); int cnt = 0; for (int i = 1; i <= n; i++) { scanf("%I64d", &color[i]); if (!vis[color[i]]) ++cnt; vis[color[i]] = 1; tree[i].clear(); } for (int i = 1; i < n; i++) { int u, v; scanf("%d%d", &u, &v); tree[u].push_back(v); tree[v].push_back(u); } printf("Case #%d: ", ++cs); if (cnt == 1) { // 只有一种颜色的特殊情况 printf("%I64d\n", (LL)n * (n - 1LL) / 2LL); continue; } ans = 0; dfs(1, -1); for (int i = 1; i <= n; i++) { // 注意最后要对整棵树来补充所有颜色剩下的联通块 if (!vis[i]) continue; ans += (n - sum[i]) * (n - sum[i] - 1LL) / 2LL; } printf("%I64d\n", (LL)n * (n - 1LL) / 2LL * cnt - ans); } return 0;}
阅读全文
0 0
- hdu6035树形dp
- HDU6035 Colorful Tree(树形dp)
- 【HDU6035】Colorful Tree(dfs,树形dp)
- 【2017多校】HDU6035 Colorful Tree 【听说是树形DP】
- HDU6035-Colorful Tree 补集思想+树形DP
- hdu6035-树形dp-2017多校(2)&难-Colorful Tree
- HDU6035 2017多校第一场1003 树形DP
- 【dp】树形dp真好玩,hdu6035多校第一场的 colorful tree
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形dp
- 树形DP
- 树形DP
- 树形DP
- 树形DP
- 树形dp
- WebSocket JAVA
- IDEA Activiti Designer插件---actiBPM汉字乱码问题
- 【iOS】视频全屏退出后,导航栏向上偏移20
- 新手学C++多线程编程(9)多线程面向对象架构和类层次C++组件
- Visual Studio 生成出错
- hdu6035树形dp
- 平稳退化的应用举例
- 抽象工厂模式
- 手机联系人的增删改
- Android--------使用BottomTabBar实现底部导航页
- 例题6-7 二叉树的层次遍历 UVa 122 Trees on the level
- Dash Based On Plotly
- href=#与href=javascript:void(0)的区别
- HDU 5527----Too Rich