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)的更多相关文章

  1. hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。

    /** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...

  2. HDU-6035 Colorful Tree(树形DP) 2017多校第一场

    题意:给出一棵树,树上的每个节点都有一个颜色,定义一种值为两点之间路径中不同颜色的个数,然后一棵树有n*(n-1)/2条 路径,求所有的路径的值加起来是多少. 思路:比赛的时候感觉是树形DP,但是脑袋 ...

  3. 回滚树形dp(按dfs序dp)——hdu6035

    本题前面的操作别的博客里都有.难点在于颜色ci的贡献,如何一次dfs求出答案 先来考虑如何在一次dfs中单独对颜色i进行计算 用遍历dfs序的方式,在深搜过程中,碰到带有颜色 i 的点 u,u每个颜色 ...

  4. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  5. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  6. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  7. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  8. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  9. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

  10. POJ2342 树形dp

    原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...

随机推荐

  1. Timer的schedule和scheduleAtFixedRate方法的区别解析

    在java中,Timer类主要用于定时性.周期性任务 的触发,这个类中有两个方法比较难理解,那就是schedule和scheduleAtFixedRate方法,在这里就用实例分析一下 (1)sched ...

  2. C语言中强制类型转换总结

    C语言中强制类型转换总结  ● 字符型变量的值实质上是一个8位的整数值,因此取值范围一般是-128-127,char型变量也可以加修饰符unsigned,则unsigned char 型变量的取值范围 ...

  3. .swp文件的恢复

    .swp 编辑文件的过程中会出现这个隐藏文件. 文件如果正常保存,.swp就会自动删除.如果不正常退出,比如关机,.swp就会留下来. linux下: ls -all 可以查看隐藏文件 命令: vi ...

  4. 哲学家就餐-同步问题解析-python

    五个哲学家吃五盘通心粉,由于通心粉很滑,所以必须要拿起左右两边的叉子才能吃到. 叉子的摆放如图所示. 那么问题来了:能为每一个哲学家写一段描述其行为的程序,保证不会出现死锁. 解法1:让他等待能够使用 ...

  5. (转\整)UE4游戏优化 多人大地型游戏的优化(一)游戏线程的优化

    施主分享随缘,评论随心,@author:白袍小道 小道暗语: 1.因为小道这里博客目录没自己整,暂时就用随笔目录结构,所以二级目录那啥就忽略了.标题格式大致都是(原or转) 二级目录 (标题) 2.因 ...

  6. Leetcode 659.分割数组为连续子序列

    分割数组为连续子序列 输入一个按升序排序的整数数组(可能包含重复数字),你需要将它们分割成几个子序列,其中每个子序列至少包含三个连续整数.返回你是否能做出这样的分割? 示例 1: 输入: [1,2,3 ...

  7. UVALive 4764 简单dp水题(也可以暴力求解)

    B - Bing it Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status ...

  8. poj 1062 昂贵的聘礼 (最短路径)

    昂贵的聘礼 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 33365   Accepted: 9500 Descriptio ...

  9. [bzoj4945][Noi2017]游戏

    题目大意:有$n$个位置,有三种数,每个位置只可以填一种数,$d(d\leqslant8)$个位置有三种选择,其他位置只有两种选择.有一些限制,表示第$i$个位置选了某种数,那么第$j$个位置就只能选 ...

  10. BZOJ[NOI2004]郁闷的出纳员 | Splay板子题

    题目: 洛谷也能评测....还有我wa了10多次的记录233 题解: 不要想得太复杂,搞一个全局变量记录一下工资的改变量Delta,这样可以等询问的时候就输出val+Delta,然后插入的时候插入x- ...