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

/**
题目:hdu6035 Colorful Tree
链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035
题意:给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。

思路:看题解后,才想出来的。树形dp。

求所有路径的值和 = 路径条数*总颜色数(n*(n-1)*colors/2)-sigma(每种颜色没有经过的路径条数)

主要是求每种颜色没有经过的路径条数。

画一棵树,我直接用颜色值表示节点编号。

             2
           /             3     4
         /     /          1     3    2
       / \   / \  /       4   5  4  5 3  5        12个点。

首先求颜色值为3的不经过的路径条数x
树上有三个3.很容易想到:
x = 最左边那个3下面的3个点构成的路径条数(3*2/2=3)+中间的3的两个子树分别构成的路径条数和(0)
+最右边的3的子树的分别构成的路径条数和(0)
+(总节点数-所有的3为根的子树节点数之和)*(总节点数-所有的以3为根的子树节点数之和-1)/2 ;

所以size[i]表示以i为根的树的节点数。

sum[i]在dfs过程中,,维护。。比如假设颜色为2.上图。 那么左子树是根为3,右子树是根为4.
那么递归完左子树之后,sum[2] = 0; 然后再递归完右子树后sum[2] = 3;就是右下角的那个2为根的子树的点数。

最终sum[i]表示所有以i颜色为根的子树的所有节点数之和。
sum[2] = 12;
sum[1] = 3;
sum[4] = 8;
sum[5] = 3;
sum[3] = 8;

*/

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 2e5+100;
int size[N];
int sum[N];
int col[N];
int vis[N];
int colors, n;
LL cnt;
vector<int> G[N];
void dfs(int r,int f)
{
    int len = G[r].size(), temp = 0;
    size[r]  = 1;
    if(sum[col[r]]!=0){
        temp = sum[col[r]];
        sum[col[r]] = 0;
    }
    for(int i = 0; i < len; i++){
        int to = G[r][i];
        if(to==f) continue;
        dfs(to,r);
        size[r] += size[to];
        cnt += (LL)(size[to]-sum[col[r]])*(size[to]-sum[col[r]]-1)/2;
        sum[col[r]] = 0;
    }
    sum[col[r]] = size[r]+temp;
}
int main()
{
    int cas = 1;
    while(scanf("%d",&n)==1)
    {
        memset(vis, 0, sizeof vis);
        memset(size, 0, sizeof size);
        memset(sum, 0, sizeof sum);
        colors = 0;
        for(int i = 1; i <= n; i++) G[i].clear();
        for(int i = 1; i <= n; i++){
            scanf("%d",&col[i]);
            if(vis[col[i]]==0){
                colors++;
            }
            vis[col[i]] = 1;
        }
        int u, v;
        for(int i = 1; i <= n-1; i++){
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        cnt = 0;
        dfs(1,-1);
        for(int i = 1; i <= n; i++){
            if(vis[i]==0) continue;
            cnt += (LL)(n-sum[i])*(n-sum[i]-1)/2;
        }
        printf("Case #%d: %lld\n",cas++,(LL)n*(n-1)/2*colors-cnt);
    }
    return 0;
}
时间: 2024-10-14 14:32:13

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

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

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

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

URAL_1018 Binary Apple Tree 树形DP+背包

这个题目给定一棵树,以及树的每个树枝的苹果数量,要求在保留K个树枝的情况下最多能保留多少个苹果 一看就觉得是个树形DP,然后想出 dp[i][j]来表示第i个节点保留j个树枝的最大苹果数,但是在树形过程中,有点难表示转移 后来看了下大神的做法才知道其实可以用背包来模拟 树枝的去留,其实真的是个背包诶,每个子树枝就相当于物品,他占用了多少树枝量,带来多少的收益,就是用背包嘛,于是用树形DP+背包就可以做了 #include <iostream> #include <cstdio> #

HDU 5834 Magic boy Bi Luo with his excited tree (树形DP)

题意:给定一棵树,每个点有个权值,每条边有权值,每经过边都会消耗相应的权值,但是点的权值只能获得一次,问你从 i 点出发能获得的最大权值是多少. 析:树形DP,就是太麻烦了,两次dfs,维护一共6个值分别是,从 i 出发的最大值并且返回 i, 从 i 出发的最大值并且不返回,从 i 出发的次大值并且不返回,从 i 出发的最大值的子树结点并且不返回,从 i 向父结点出发的最大值并且不返回,从 i 向父结点出发的最大值并且返回. 第一次dfs就能求出前四个,第二个dfs维护后面两个. 答案就是  m

ZOJ 3201 Tree of Tree (树形DP)

题意:给定一棵树,求大小为k的一个子树的最大权值. 析:dp[i][j] 表示以 i 为根大小为 j 时最大权值.dp[i][j] = max{dp[i][j-k] + dp[son][k]},状态方程. 有一个要注意,因为要选的是一棵子树,所以以哪个点为根都行,也就是说,对于任意子树都能找一个合适的根,使得不会出现父结点与子结点冲突. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <

Bestcoder round #65 &amp;&amp; hdu 5593 ZYB&#39;s Tree 树形dp

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 354    Accepted Submission(s): 100 Problem Description ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no m

codeforces161D - Distance in Tree 树形dp

题意:给你一棵树,问你树中距离为k的有多少种情况. 解题思路:树形dp  维护每个节点(1-K)深度的情况, 解题代码: 1 // File Name: 161d.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月03日 星期日 19时20分10秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #incl

hdu5593/ZYB&#39;s Tree 树形dp

ZYB's Tree Memory Limit: 131072/131072 K (Java/Others) 问题描述 ZYBZYB有一颗NN个节点的树,现在他希望你对于每一个点,求出离每个点距离不超过KK的点的个数. 两个点(x,y)(x,y)在树上的距离定义为两个点树上最短路径经过的边数, 为了节约读入和输出的时间,我们采用如下方式进行读入输出: 读入:读入两个数A,BA,B,令fa_ifa?i??为节点ii的父亲,fa_1=0fa?1??=0;fa_i=(A*i+B)\%(i-1)+1fa

hdu 5379 Mahjong tree 树形dp

链接 题意:给定一棵树 把1-n填到树的节点上,使得: 1:儿子节点上填的数字是连续的. 2:子树节点上填的数字是连续的. 把儿子节点分成两种,一种是叶子节点,一种是非叶子节点. 显然非叶子节点个数不能超过2个,不然就不存在这样的方案了. 然后分类讨论一下非叶子节点个数即可. #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <cstdio> #i