hdu6035(树形DP)
hdu6035
题意
给出一棵树,现在定义两点之间距离为两点间最短路径上颜色集合的大小。问任意两点间距离之和。
分析
换个方向,题目其实等价于求每种颜色在多少条路径上出现过(每种颜色对于答案的贡献),然后求和。
直接求不好求,但是我们可以求每种颜色在多少条路径上没有出现过,对于颜色 \(a\),我们删掉所有颜色为 \(a\) 的节点,那么树会被分成一个个树块或单个节点,那么一个大小为 \(3\) 的树块,显然有 \(3\) 条路径不包含颜色 \(a\),求和即可。实际上借助这个思想,而不用真的这么做。
设 \(sons[u]\) 数组为以 \(u\) 为根节点的子树的大小,\(sum[i]\) 表示颜色 \(i\) 已经合并的树块的大小。(比如说颜色为 a 的某个节点已经合并了它的两个不同颜色的子节点,那么如果它的父亲节点或上面的节点颜色也为 a ,那么递归结束回到上面的时候就要排除下面那两个不同颜色节点的影响,所以要合并到颜色 a 里面去)
\(s\) 记录在向上合并的过程中某个颜色在其未出现的块里能形成多少条路径。
设 \(u\) 是 \(v\) 的父亲节点,ct = sons[v] - sum[c[u]] + pre
计算的是从当前点 \(v\) 到下面每条链下最近的颜色为 \(c[u]\) 的节点之间的节点的数量,说明这些点还未合并到 \(c[u]\) 这个颜色里面,所以算出路径数累计到 \(s\) 里面,其中,\(sons[v]\) 可以理解成以 \(v\) 为根的子树的大小 , \(sum[c[u]]\) 表示下面 \(c[u]\) 这个颜色已经合并多少节点了,注意到 \(pre\) 的初始值为 \(sum[c[u]]\) ,也就是说 \(- sum[c[u]] + pre\) 保证我们算的是当前这颗子树下的未被合并的节点数量(因为我们前面可能先遍历了其它子树)。
最后,除了颜色 \(c[1]\) 能全部合并完( \(sum[c[1]] = n\) ,因为我们从 \(1\) 开始向下 \(DFS\) ),其它的可能未完全合并(节点 \(1\) 可能有多个子节点),\(n - sum[i]\) 为颜色 \(i\) 还未合并的节点的数量(且这些节点一定是连在一起的)。
合并的意思不是说某个颜色合并了这个块,其它颜色不能合并了,事实上每种颜色都要向上合并,最终只有颜色 \(c[1]\) 能合并完,那是因为我们是从 \(1\) 开始向下 \(DFS\) 。合并的意思也可以理解为:\(a\) 这个颜色合并了它下面的块,那么它及它下面的块对于所有上面颜色为 \(a\) 的节点都无意义了(想想前面通过删掉相同颜色的节点对树分块的思想)。
code
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
int kase = 1;
int n, c[MAXN];
int vis[MAXN];
int head[MAXN << 1], cnt;
struct Edge {
int to, next;
}e[MAXN << 1];
void addedge(int u, int v) {
e[cnt].to = v;
e[cnt].next = head[u];
head[u] = cnt++;
}
ll s;
ll sum[MAXN]; // 合并下面的节点成块
int sons[MAXN];
void dfs(int fa, int u) {
sons[u] = 1;
sum[c[u]]++;
ll pre = sum[c[u]];
for(int i = head[u]; ~i; i = e[i].next) {
int v = e[i].to;
if(v != fa) {
dfs(u, v);
sons[u] += sons[v];
ll ct = sons[v] - sum[c[u]] + pre;
s += 1LL * ct * (ct - 1) / 2;
sum[c[u]] += ct;
pre = sum[c[u]];
}
}
}
int main() {
while(~scanf("%d", &n)) {
memset(head, -1, sizeof head); cnt = 0;
s = 0;
memset(sum, 0, sizeof sum);
memset(vis, 0, sizeof vis);
int num = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &c[i]);
if(!vis[c[i]]) {
num++;
vis[c[i]] = 1;
}
}
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
addedge(u, v);
addedge(v, u);
}
dfs(0, 1);
ll ans = 1LL * num * n * (n - 1) / 2 - s;
for(int i = 1; i <= n; i++) {
if(vis[i]) {
ll ct = n - sum[i];
ans -= ct * (ct - 1) / 2;
}
}
printf("Case #%d: %lld\n", kase++, ans);
}
return 0;
}
hdu6035(树形DP)的更多相关文章
- hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。
/** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...
- HDU-6035 Colorful Tree(树形DP) 2017多校第一场
题意:给出一棵树,树上的每个节点都有一个颜色,定义一种值为两点之间路径中不同颜色的个数,然后一棵树有n*(n-1)/2条 路径,求所有的路径的值加起来是多少. 思路:比赛的时候感觉是树形DP,但是脑袋 ...
- 回滚树形dp(按dfs序dp)——hdu6035
本题前面的操作别的博客里都有.难点在于颜色ci的贡献,如何一次dfs求出答案 先来考虑如何在一次dfs中单独对颜色i进行计算 用遍历dfs序的方式,在深搜过程中,碰到带有颜色 i 的点 u,u每个颜色 ...
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- COGS 2532. [HZOI 2016]树之美 树形dp
可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...
- 【BZOJ-4726】Sabota? 树形DP
4726: [POI2017]Sabota? Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 128 Solved ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- 树形DP
切题ing!!!!! HDU 2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- POJ2342 树形dp
原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...
随机推荐
- sublime text基本配置备份
sublime text基本配置备份: // Settings in here override those in "Default/Preferences.sublime-settings ...
- NGUI注册事件的三种方式
1.第一种方式 当一个元素要执行某个方法,而这个方法在此元素赋予的脚本上有,那么直接会调用此方法,但此方法的名称必须是内置的固定名称,例如OnClick,OnMouseOver,OnMouseOut等 ...
- PoolManager
我用的PoolManager版本是5.5.2的,导入的包总共有三个文件夹:Editor,Plugins,PoolManagerExampleFiles 1.Editor这个文件夹里面的东西,顾名思义, ...
- ASP.NET Core API ---状态码
摘录自:https://www.cnblogs.com/cgzl/p/9047626.html 状态码是非常重要的,因为只有状态码会告诉API的消费者: 请求是否如预期的成功,或者失败 如果出现了错误 ...
- Entity Framework(四)--EF原理和状态管理
一.原理: 如何查看真正执行的SQL是怎样的? DbContext有一个Database属性,Database属性有一个Log属性,是Action委托类型其中的参数就是sql语句,每次EF执行sql语 ...
- Python 第一周编程作业
一. 编程题 1. 结合turtle库使用手册,读懂下列代码,并在jupyter编译器中运行观察结果: 依次分析下代码: 第一行 通过保留字import引用了Python中用于绘制图形的turtl ...
- 团队项目-任务分解[Alpha0]
团队项目-任务分解[Alpha0] 标签(空格分隔): 团队博客 适用范围: 本文档 适用对象 团队全体成员 适用时间 alpha阶段第一周计划 10.24-10.28 适用内容 目标.分工.时长估计 ...
- OpenFlow-Enaling innvation in Campus Networks
OpenFlow-Enaling innvation in Campus Networks 出现问题 背景 Networks have become part of the critical infr ...
- 【干货】2个小时教你hexo博客添加评论、打赏、RSS等功能 (转)
备注:该教程基于Hexo 2.x版本,目前Hexo是3.x版本,照本教程实现有可能会出现404错误,笔者目前还未找时间去解决,待笔者找时间解决该问题后,再写一篇该问题的解决教程,给各位读者带来困扰,还 ...
- SQL SERVER 2008 bug
我把一个数据的数据导入的到另外一个数据库 作为 测试库使用. 发现里面设置为唯一标识ID 自动增长的表 全部默认是否. 最后只能手动一个个 表全部改过来. 弄了好久才发现这个问题.浪费了我几个小时的 ...