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个人去 ,根据题意我们可以很容易的得到如下递推公式 ...
随机推荐
- 《Cracking the Coding Interview》——第11章:排序和搜索——题目2
2014-03-21 20:49 题目:设计一种排序算法,使得anagram排在一起. 解法:自定义一个comparator,使用额外的空间来统计字母个数,然后比较字母个数. 代码: // 11.2 ...
- Python面试题之一:解密
Python面试题之一: 说明:就是Python工程师面试题 一.字典转换与正则提取值 1:key与Value交换 a = {'a':1,'b':2} print({value:key for key ...
- Day4 自定义控件/ListView/RecyclerView
创建自定义控件 引入布局 在新增的title.xml中创建一个自定义的标题栏: <LinearLayout xmlns:android="http://schemas.android. ...
- 转:npm install 时总是报phantomjs-prebuilt@2.1.14安装失败
该文章转自:http://www.cnblogs.com/alice626/p/6206722.html 在npm install时总是报如下错误, 尝试单独安装:npm install phanto ...
- 【多线程学习(2)】继承Thread类和实现Runnable接口、Callable接口的区别
1)Runnable和Callable同是接口 * Callable的任务执行后可返回值,而Runnable的任务是不能返回值(是void);call方法可以抛出异常,run方法不可以 * 运行Cal ...
- HDU 3856 Palindrome ( Manacher + RMQ + 二分 ) WA!!!
不知道错在哪了,求大神指教!!! 思路:用manacher求出每个以str[i]为中心轴的回文串的长度,RMQ预处理区间最大值,对于每个查询,二分最大回文串长,判定是否可行. #include < ...
- 团队冲刺Alpha(七)
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- 初识 HTML5(一)
H5其实就是H4的一个增强版本,我们在利用H5进行网页的构造会更简便,标签语义更简洁明了.首先,我们要理解HTML4,它是HTML的标记+css2+JavaScript的一些基本应用,简言之,就是AP ...
- 通过命令行安装或卸载Tomcat服务
一.安装Tomcat服务 1.打开命令提示符 方法1: 按住win+R,打开运行,输入cmd,打开命令提示符 方法2:在开始菜单>所有程序>附件>命令提示符 2. 通过命令进入到to ...
- c#中onclick事件请求的两种区别
在C#中如果是asp控件的button有两个click的调用,一个是OnClick,一个是OnClientClick.那么这两者有什么区别呢,下面就来说说区别. <asp:Button ID=& ...