hdu 多校联赛 Colorful Tree

Colorful Tree

HDU - 6035                             
There is a tree with n nodes, each of which has a type of color represented by an integer, where the color of nodei is ci.

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(n1)2
paths in total.
Input The input contains multiple test cases.

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

Next line contains n integers where the i-th integer represents ci, the color of node i.(1cin)

Each of the next n1 lines contains two positive integers x,y(1x,yn,xy), meaning an edge between node x and node y
.

It is guaranteed that these edges form a tree.
Output For each test case, output " Case #x :y" in one line (without quotes), where x indicates the case number starting from 1 and y 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
(由于hdu登不上了 只能从vjudge上赋值过来了 原题连接:http://acm.hdu.edu.cn/showproblem.php?pid=6035)
比赛的时候这节没看懂题意 样例都解释不了 后来多方打听才真正呢个的理解题意 

题意

树上每个节点有一种颜色ci(1<=ci<=n)2<=n<=2105,每个点对的路径值为这个路径上的颜色种数,求树上所有路径(n(n1)/2条路径)的长度和

思路

直接计算每个颜色对答案的贡献


自己的代码就是这样写的,感觉自己的思路说出来不是很好理解 = =,大家看不懂的话可以看第二种思路。

首先如果树上每个点的颜色都不同的话,那么答案就是每个点经过路径的数量之和,可是在问题中有的点的颜色会相同,所以有的路径不能走。

考虑用dfs的方法解题,dfs中我们遇到的第一个点,因为之前没有遇到其它点,所以显然这个点对答案的贡献就是经过它的所有路径(各个子树大小相乘),接着往下dfs,如果其子树中节点的颜色与第一个点的颜色不同,那么自然再统计一次就好(各个子树大小相乘,其中子树包括其父节点),但是有可能这个节点的颜色和第一个节点的颜色相同,那么这个节点向上只有一个联通块可以走,但是向下仍然可以访问其所有子节点。所以此题的关键是维护好与一个节点颜色相同的父节点之间的联通块大小,这个联通块的定义大致就是,一个父节点的子树大小,减去所有与其颜色相同的子节点子树大小。一父节点下方的联通块大小首先是其子树的大小,然后遇到一个相同颜色的子树,就减去这个子树的大小即可。考虑到某一个颜色的第一个节点没有与其颜色相同的父节点,所以加一个虚根。

联通块
如图,点1是父节点,点2对应的父节点联通块就是粉色部分,点3对应的联通块是橙色部分(因为点4还没有访问,所以访问了这里没有关系)点4是蓝色部分

自己的统计方法是先算父节点联通块与自身代表子树的路径条数,然后算自身子树的路径条数。

计算出答案上限,减去非法值

很多网上的代码和标程都是这样写的。

首先,颜色不会超过n种,那么我们假设每条路径上都有n种颜色,共有n(n1)/2条路径,答案就为ans=nn(n1)/2。我们从中减去非法的,或者说重复计算的值即为答案。

如何统计重复计算的值呢?利用前面说的联通块,一个联通块里面是不会出现与这个父节点颜色相同的节点的,设某个联通块的大小为siz,遍历某个颜色的所有节点,这些节点对应的联通块内部的路径都不会出现这个颜色,所以答案要减去siz(siz1)。统计结束后答案就被计算出了。

标程用到了dfs序的方法来统计联通块的大小(用dfs序来判断节点之间的父子关系)。

具体代码实现部分会在代码里解释

ac代码:

#include 
using namespace std;
const int N = 4e5+100;
typedef long long ll;
int c[N],vis[N];//c[i]表示第i个点的颜色,vis[i]表示的是i这个颜色有没有出现过 用于标记点
vector e[N];//创建容器组 用于存储图
ll sum[N],size[N];//sum[i]表示的是这个颜色i所能管理的点,size[i]表示的是以i为根的点的个数
ll ans;
void dfs(int x,int y)
{
    size[x]=1;//指的是x为根的树的点的个数 加上他本上则+1
    sum[c[x]]++;// sum是指 当前颜色的所能管理的点(包括自身的总个数) 那么每种颜色 最后都是一个接近根的值
    //到不了根的部分 就要在后面剔除
    ll pre=sum[c[x]];// 指从根到 x ,c[x] 管辖的点的总个数
    for(int i=0; i



n ( n 1 ) / 2

你可能感兴趣的:(ACM,ACM题目解析,杭电多校联赛)