HDU-6035:Colorful Tree(虚树+DP)

这里有三道长得像的题:

一:HDU6036:

There is a tree with nn nodes, each of which has a type of color represented by an integer, where the color of node ii is cici.

The path between each two different nodes is unique, of which we define the value as the number of different colors appearing in it.

Calculate the sum of values of all paths on the tree that has n(n−1)/2 paths in total.

InputThe input contains multiple test cases.

For each test case, the first line contains one positive integers nn, indicating the number of node. (2≤n≤200000)(2≤n≤200000)

Next line contains nn integers where the ii-th integer represents cici, the color of node ii. (1≤ci≤n)(1≤ci≤n)

Each of the next n−1n−1 lines contains two positive integers x,yx,y (1≤x,y≤n,x≠y)(1≤x,y≤n,x≠y), meaning an edge between node xx and node yy.

It is guaranteed that these edges form a tree.OutputFor each test case, output " Case #xx: yy" in one line (without quotes), where xxindicates the case number starting from 11 and yy denotes the answer of corresponding case.Sample Input

3
1 2 1
1 2
2 3
6
1 2 1 3 2 1
1 2
1 3
2 4
2 5
3 6

Sample Output

Case #1: 6
Case #2: 29

题意:求出所有路径的颜色种类之和。

二:洛谷P2664

题目描述

lrb有一棵树,树的每个节点有个颜色。给一个长度为n的颜色序列,定义s(i,j) 为i 到j 的颜色数量。以及

现在他想让你求出所有的sum[i]

输入输出格式

输入格式:

第一行为一个整数n,表示树节点的数量

第二行为n个整数,分别表示n个节点的颜色c[1],c[2]……c[n]

接下来n-1行,每行为两个整数x,y,表示x和y之间有一条边

输出格式:

输出n行,第i行为sum[i]

输入样例#1:


1 2 3 2 3 
1 2 
2 3 
2 4 
1 5

输出样例#1:

10 

11 

12

说明

sum[1]=s(1,1)+s(1,2)+s(1,3)+s(1,4)+s(1,5)=1+2+3+2+2=10 
sum[2]=s(2,1)+s(2,2)+s(2,3)+s(2,4)+s(2,5)=2+1+2+1+3=9 
sum[3]=s(3,1)+s(3,2)+s(3,3)+s(3,4)+s(3,5)=3+2+1+2+3=11 
sum[4]=s(4,1)+s(4,2)+s(4,3)+s(4,4)+s(4,5)=2+1+2+1+3=9 
sum[5]=s(5,1)+s(5,2)+s(5,3)+s(5,4)+s(5,5)=2+3+3+3+1=12

对于40%的数据,n<=2000 
对于100%的数据,1<=n,c[i]<=10^5

 题意:求出每个点到其他点路径的颜色种类和。

三:Wannafly挑战赛19C:多彩的树

有一棵树包含 N 个节点,节点编号从 1 到 N。节点总共有 K 种颜色,颜色编号从 1 到 K。第 i 个节点的颜色为 Ai
Fi 表示恰好包含 i 种颜色的路径数量。请计算:

输入描述:

第一行输入两个正整数 N 和 K,N 表示节点个数,K 表示颜色种类数量。第二行输入 N 个正整数, 表示节点的颜色。

接下来 N - 1 行,第 i 行输入两个正整数 Ui 和 Vi,表示节点 Ui 和节点 Vi 之间存在一条无向边,数据保证这 N-1 条边连通了 N 个节点。

1 ≤ N ≤ 50000.
1 ≤ K ≤ 10.
1 ≤ Ai ≤ K.

输出描述:

输出一个整数表示答案。
输入例子:
5 3
1 2 1 2 3
4 2
1 3
2 1
2 5
输出例子:
4600065

-->

示例1

输入

5 3
1 2 1 2 3
4 2
1 3
2 1
2 5

输出

4600065

题意:对于L=[1,K],统计有多少路径的颜色种类=L;

------------------------------------------分界线-------------------------------------------------

对于第三题,可以容斥搞定。 前面两题可以借助虚树来做。

第三题,容斥,因为K<=10,只有2^K种颜色组合,按照每种颜色组合,用并查集分块。求出块的数量...反正一系列常规操作,最后容斥减去,这里和虚树无关,就不讲了。

第二题,因为要针对每一个点来求,所以考虑虚树加差分。

第一题,因为只计算最后的总结果,所以可以直接一次性操作完。

具体的,对于第二题:对于每种颜色,我们用是这种颜色的点来建立虚树,假设现在按照颜色C得到了一个虚树:虚树的边代表了一个不含颜色C的连通块,还有一些不含颜色C的连通块在虚树的叶子节点下边的连通块虚树的根的上面的连通块。 对于C颜色对其他点的贡献:颜色是C的点,显然它的结果是N,(即它到每个点的路径都会包含这种颜色);否则,它的结果是N-所在连通块的大小。 因为一个连通块的结果是相同的,所以我们用差分来统计:即在这个连通块的最高点+ans,所有最低点的儿子-ans,那么求得的前缀和就是结果。            每种颜色都这么干,最后累加一次前缀和,得到每个点的结果。复杂度就是O(N*17)。17是求LCA的复杂度。

对于第三题:可以像第二题那么干,那么ans=(Σ sum[i] )/2。也可以用更高效的统计方法。 同样需要用虚树的思想去想,但是累计的时候一起累计。那么一次DFS就可以完事了。

【第三题可以参考】:https://blog.csdn.net/Bahuia/article/details/76141574

原文地址:https://www.cnblogs.com/hua-dong/p/9279825.html

时间: 2024-10-10 04:38:00

HDU-6035:Colorful Tree(虚树+DP)的相关文章

hdu 6035 Colorful Tree(树形dp+技巧)

题目链接:hdu 6035 Colorful Tree 题意: 给你一棵树,每个节点有一种颜色,现在让你求所有点对的路径上不同的颜色数量的总和. 题解: 下面是官方题解: 单独考虑每一种颜色,答案就是对于每种颜色至少经过一次这种的路径条数之和.反过来思考只需要求有多少条路径没有经过这种颜色即可.直接做可以采用虚树的思想(不用真正建出来),对每种颜色的点按照 dfs 序列排个序,就能求出这些点把原来的树划分成的块的大小.这个过程实际上可以直接一次 dfs 求出. 这里的所说的单独考虑每种颜色,指的

Codeforces 1111E Tree 虚树 + dp

直接把 r 加进去建虚树, 考虑虚树上的dp, 我们考虑虚树的dfs序的顺序dp过去. dp[ i ][ j ]  表示到 i 这个点为止, 分成 j 组有多少种合法方案. dp[ i ][ j ] = dp[ i - 1 ][ j ] * (j - have[ i ])  + dp[ i - 1 ][ j - 1 ], have[ i ] 表示 i 的祖先中有多少个在a中出现. #include<bits/stdc++.h> using namespace std; const int N

HDU 6035 Colorful Tree(dfs)

题意:一棵有n个点的树,树上每个点都有颜色c[i],定义每条路径的值为这条路径上经过的不同颜色数量和.求所有路径的值的和. 可以把问题转化为对每种颜色有多少条不同的路径至少经过这种颜色的点,然后加和.求有多少条路径经过可以转换为总路径数-没有经过的路径数,只要求出没有经过的路径数就好了. 对于每一个相同颜色的点,它们将树割成一些个联通块,显然这些联通块内部之间的路径不会经过这种颜色. 于是问题转化为求点划分的联通块大小. 用类似于虚树的dfs办法,每次维护树上最左边的一段链,然后用栈进行数据的更

hdu 3016 Man Down (线段树 + dp)

题目大意: 是男人就下一般层...没什么可以多说的吧. 注意只能垂直下落. 思路分析: 后面求最大值的过程很容易想到是一个dp的过程 . 因为每一个plane 都只能从左边 从右边下两种状态. 然后我们所需要处理的问题就是 ,你如何能快速知道往左边下到哪里,往右边下到哪里. 这就是线段树的预处理. 讲线段按照高度排序. 然后按照高度从小到大加入到树中. 然后去寻找左端点 和 右端点最近覆盖的线段的编号. #include <cstdio> #include <iostream> #

hdu 1754 splay tree伸展树 初战(单点更新,区间属性查询)

题意:与区间查询点更新,点有20W个,询问区间的最大值.曾经用线段树,1000+ms,今天的伸展树,890没ms,差不多. 第一次学习伸展树,一共花了2个单位时间,感觉伸展树真很有用,也很好玩.现在只学了一点点.切个点更新试试. 大致思路:用编号(数组)作为树的键值建树,每插一个数,沿路节点更新最大值(每个结点有一个附加信息标记以之为子树的树所有点的最大值).所以,查询时[i,j],只要把i-1伸展到树根,把j+1伸展到I-1下面,那么j+1的左子树就是要的区间了!查该子树根值信息即可(特判端点

bzoj 3572 [Hnoi2014]世界树(虚树+DP)

3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 645  Solved: 362[Submit][Status][Discuss] Description 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石.     世界树的形态可以用一个数学模型来描述:世界树中有n个

hdu 5379 Mahjong tree(树形dp)

题目链接:hdu 5379 Mahjong tree 树形dp,每个节点最多有2个子节点为一棵节点数大于1的子树的根节点,而且要么后代的节点值都大于,要么都小于本身(所以tson不为0是,要乘2).对于K个单一节点的子节点,种类数即为全排K!.当一个节点没有兄弟节点时,以这个节点为根结点的子树,根可以选择最大或者最小. #pragma comment(linker, "/STACK:102400000,102400000") #include <cstdio> #inclu

BZOJ 3572: [Hnoi2014]世界树 [虚树 DP 倍增]

传送门 题意: 一棵树,多次询问,给出$m$个点,求有几个点到给定点最近 写了一晚上... 当然要建虚树了,但是怎么$DP$啊 大爷题解传送门 我们先求出到虚树上某个点最近的关键点 然后枚举所有的边$(f,x)$,讨论一下边上的点的子树应该靠谁更近 倍增求出分界点 注意有些没出现在虚树上的子树 注意讨论的时候只讨论链上的不包括端点,否则$f$的子树会被贡献多次 学到的一些$trick:$ 1.$pair$的妙用 2.不需要建出虚树只要求虚树的$dfs$序(拓扑序)和$fa$就可以$DP$了 注意

hdu 3333 Turing Tree(线段树)

题目链接:hdu 3333 Turing Tree 题目大意:给定一个长度为N的序列,有M次查询,每次查询l,r之间元素的总和,相同元素只算一次. 解题思路:涨姿势了,线段树的一种题型,离线操作,将查询按照右区间排序,每次考虑一个询问,将mv ~ r的点全部标记为存在,并且对于每个位置i,如果A[i]在前面已经出现过了,那么将前面的那个位置减掉A[i],当前位置添加A[i],这样做维护了每个数尽量做,那么碰到查询,用sum[r] - sum[l-1]即可. #include <cstdio>