题目链接:https://vjudge.net/problem/HDU-6035

题目大意:

  多样例输入。

  对于每一个样例,给出 n \((2 \le n \le 200000)\) 个结点的一棵树,各个节点都有各自的颜色 \(c_i  (1 \le c_i \le n)\),树上任意两点之间的路径的权值为该路径经过的不同颜色的结点数,求树上所有两点路径的权值之和。

知识点:  树、DFS

解题思路:

  求树上所有的两点路径的权值之和,可以转化为求各个颜色在各条路径中的贡献值(即该颜色能够为树上的各条路径增加的权值的总和,也可以理解成是该颜色在多少条路径中出现)。但是,并没有非常好的方法可以直接求出这个总的贡献值,于是,我们可以反过来求:各个颜色在多少条路径中没有出现。

  如图1所示,树上所有的红色结点将整棵树分成了 5 个联通块(笔者已用 1~5 标出),则这五个联通块里面的所有路径显然都没有经过红色结点。其实这些联通块也可以看成是一棵子树,对于一棵有 n 个结点的树,树上所有路径数为 \(\frac{n(n-1)}{2}\) 1

  那么,我们所要求的答案其实就是\(\frac{NumberOfColors \times n \times (n-1)}{2}\) - 没有经过各个颜色的所有路径数

  对于每一种颜色,没有经过该种颜色的路径可以分成两类:

  1、从树根以下,到第一次接触颜色点之前的这一联通块的路径(如图1中的第1块);

  2、颜色点之间和颜色点以下直到叶子的联通块(如图1中的第2~5块)。

  只要算出这两种路径的总数,即可求出答案,但此题的实现并不简单,请看代码及注释:

AC代码:

 #include <cstdio>
#include <vector>
#include <set> using namespace std;
typedef long long ll;
const int maxn=+; int color[maxn];//记录各个结点的颜色
ll sum[maxn];//精髓所在
ll sizes[maxn];//记录各个结点以下的结点数
vector<int> tree[maxn];//记录树
set<int> col;
ll ans;
void find_size(int fa,int gfa){//找出各点的 sizes[i]
sizes[fa]=;
for(int i=;i<tree[fa].size();i++){
if(tree[fa][i]==gfa) continue;
find_size(tree[fa][i],fa);
sizes[fa]+=sizes[tree[fa][i]];
}
}
void find_ans(int fa,int gfa){
ll tmp=;
if(sum[color[fa]]!=){
//此处 sum[color[fa]] 记录的是目前已知的从各个分枝的第一个颜色为 color[fa] 的点到叶子的结点数,那么当最后求出这个值以后,上文提及的第一类路径的结点数即为 n-sum[i]
tmp=sum[color[fa]];
sum[color[fa]]=;
/* ***************** */
}
for(int i=;i<tree[fa].size();i++){
if(tree[fa][i]==gfa) continue;
find_ans(tree[fa][i],fa);
//此处sum[color[fa]]用于求从 tree[fa][i] 这个结点出发到下一个颜色为 color[fa] 或者叶子的联通块的结点数
//请注意上下两处划线处的代码
ans-=(sizes[tree[fa][i]]-sum[color[fa]])*(sizes[tree[fa][i]]-sum[color[fa]]-)/;
sum[color[fa]]=;
/* ***************** */
}sum[color[fa]]=sizes[fa]+tmp;
}
int main(){
int n,a,b;
int kase=;
while(scanf("%d",&n)==){
col.clear();
for(int i=;i<=n;i++){
sum[i]=;
tree[i].clear();
}
for(int i=;i<=n;i++){
scanf("%d",&color[i]);
col.insert(color[i]);
}
ans=(ll)col.size()*n*(n-)/;
for(int i=;i<n;i++){
scanf("%d%d",&a,&b);
tree[a].push_back(b);
tree[b].push_back(a);
}find_size(,);
find_ans(,);
set<int>::iterator pt=col.begin();
for(;pt!=col.end();pt++){
int cl=*pt;
ans-=(n-sum[cl])*(n-sum[cl]-)/;
}
printf("Case #%d: %lld\n",kase++,ans);
}return ;
}

  

  

1、n(n-1)/2——此处的公式可能会挂,原因不明......

HDU6035 Colorful Tree的更多相关文章

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

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

  2. hdu-6035 Colorful Tree

    题目意思是计算所有路径(n*(n-1)/2)经过的不同颜色的数目和. 这个数目和可以转化为每种颜色经过的路径数目的求和,而这个求和又等价于颜色总数*n*(n-1)/2-没有经过某种颜色的边的数量的求和 ...

  3. 【树形dp】hdu6035 Colorful Tree

    非常棒的题解,我就不复述了:http://blog.csdn.net/Bahuia/article/details/76141574 O(n) #include<cstdio> #incl ...

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

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

  5. HDU6035:Colorful Tree(树形DP)

    传送门 题意 给出一棵最小生成树及每个节点的颜色,询问\(\frac{n(n-1)}2\)条路径的权值和,一条路径的权值为该路径的颜色种数 分析 勉强理解了ftae的做法,但是代码还是不太会,还是太弱 ...

  6. 2017 Multi-University Training Contest - Team 1 1003&&HDU 6035 Colorful Tree【树形dp】

    Colorful Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  7. AtCoder Beginner Contest 133 F Colorful Tree

    Colorful Tree 思路: 如果强制在线的化可以用树链剖分. 但这道题不强制在线,那么就可以将询问进行差分,最后dfs时再计算每个答案的修改值, 只要维护两个数组就可以了,分别表示根节点到当前 ...

  8. HDU 6035 - Colorful Tree | 2017 Multi-University Training Contest 1

    /* HDU 6035 - Colorful Tree [ DFS,分块 ] 题意: n个节点的树,每个节点有一种颜色(1~n),一条路径的权值是这条路上不同的颜色的数量,问所有路径(n*(n-1)/ ...

  9. [HDU6793] Tokitsukaze and Colorful Tree

    题目 又是一个条历新年,窗前的灼之花又盛开了. 时隔多年,现在只有这一棵树上盛开着残存的 \(n\) 朵灼之花了. 尽管如此,这些灼之 花仍散发出不同色彩的微弱的光芒. 灼之花的生命极为短暂,但它的花 ...

随机推荐

  1. Linux硬盘分区知识

    前言 硬盘使用前,一般要分区,格式化(创建文件系统)<== 存放数据 类比,房子使用前,一般要隔断,装修,买家具,再住人. 分区 一块硬盘: 主分区.扩展分区.逻辑分区 主分区+扩展分区的数量& ...

  2. 写给Java程序员的Java虚拟机学习指南

    大家好,我是极客时间<深入拆解Java虚拟机>作者.Oracle Labs高级研究员郑雨迪.有幸借这个专题的机会,能和大家分享为何Java工程师要学Java虚拟机?如何掌握Java虚拟机? ...

  3. 自定义fastjson对枚举类型的序列化及反序列化过程

    通常,fastjson在序列化及反序列化枚举时,一般以下几种策略: 1).根据枚举的name值序列化及反序列化(默认) 2).根据枚举的ordinal序列化及反序列化 3).根据枚举的toString ...

  4. C++编程入门题目--No.2

    题目:企业发放的奖金根据利润提成.利润(I)低于或等于10万元时,奖金可提10%:利润高 于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提 成7.5%:20万到4 ...

  5. 基于tp3开发的cms-前台代码执行

        内核 thinkphp PbootCMS-V1.2.1 ├─ apps         应用程序 │  ├─ admin     后台模块 │  ├─ api       api模块 │  ├ ...

  6. 前缀和(P2697 宝石串)

    前言 每次做出来什么本来做不出的题目,就忍不住记录一下.不过大多时候隔几天来看,就发现,啊,我当时只是做了一道这么弱智的题目呀,哈哈.前缀和确实不算太难.. 传送门 题目大意: 给你一个字符串只含G和 ...

  7. rsync 服务及部署

    1 rsync简介 1.1 什么是rsync rsync: - a fast, versatile, remote (and local) file-copying toolrsync:是一种快速,多 ...

  8. zabbix 告警信息与恢复信息

    名称: Action-Email 默认接收人: 故障{TRIGGER.STATUS},服务器:{HOSTNAME1}发生: {TRIGGER.NAME}故障! 默认信息: 告警主机:{HOSTNAME ...

  9. nginx反向代理做负载均衡以及使用redis实现session共享配置详解

    1.为什么要用nginx做负载均衡? 首先我们要知道用单机tomcat做的网站,比较理想的状态下能够承受的并发访问在150到200, 按照并发访问量占总用户数的5%到10%技术,单点tomcat的用户 ...

  10. 编译nginx的时候报错 需要安装PCRE

    ./configure --prefix=/mynginx/ 本地编译nginx的时候 报错 提示需要安装PCRE 错误信息: ./configure: error: the HTTP rewrite ...