题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035

题意:一棵树有n个点,每个点有自己的颜色,任意两个不同的点可以组成一条路径。也就是说一共有n(n-1)/2条不同的路径,每条路径的价值等于这条路径上颜色的数量,求所有路径的总价值。

思路:这道题采用补集的思想,我们假设总共有m个颜色出现,一共有n(n-1)/2条路径,我们假设每条路径都有m种颜色出现总价值就是m*n(n-1)/2。那么我们只要减去每种颜色在哪些路径中没有出现过,就可以得到答案。

具体做法:我们都下过围棋吧!我们把一棵树的点看成一个棋盘上棋子,被同颜色的棋子围在其中的点,和外面的点的所形成的路径都是要经过这种颜色的。而内部的点两两之间所形成的路径是不存在这种颜色,是我们需要减去的。

那么我们怎么得到这个被围在中间的点的数量呢?

题解中提到一个虚树思想。其实就是维护一个dfs过程中的值(用数组构造),在这里我们维护一个某一个颜色的dfs完返回到这个点的时候这个点下方与这个点颜色相同的点为根的子树大小。

我们现在开始模拟程序的过程。

对于1节点,5节点和6节点与它颜色相同,5节点为根的子树大小为3,6节点为根的子树大小也为3,那么实际上被围在中间的点就是1节点两个后续后续节点为根的子树大小(分别是2节点和3节点),我们把2节点为根的树的大小减去5节点为根数的大小得到2就是被1节点和5节点围在中间的点的个数。3节点为根的树的大小减去6节点为根的树的大小得到被1和6节点围在中间的点的个数。那么我们怎么得到5为根的点的个数和6为根点的个数呢?

我们dfs(左边先dfs)从1开始我们一路一下当前红色节点为根的子树大小为0,我们记录一个这个值s1,然后一路dfs到底然后返回,假设我们dfs返回到5的时候,我们已经知道5的大小是3,从而我们把sum[red]更新为3。然后返回到1,我们知道对1节点的2这个子树中红色颜色为根的最大子树大小为3(通过3-0),而2这个子树的带下为5,说明有两个点不是被围在中间。这个时候我们记录一个完成2子树这个支路我们已经把红色为根子树大小已经从0更新为3,把s1更新为3。

然后我们进入1的右子树3,一路dfs到底返回到6,假设我们知道6的带下是3,那么我们应该把sum[red]+=3=6,然后返回到1的时候我们发现sum[red]-s1=3,说明3这个支路下面有有一颗大小为3颜色是红色子树6。那么被围在中间的点就是3为根树的大小减去6为根子树的大小得到被围在中间的点为5-3=2

最后1也是一颗别人的子树,我们在返回的时候需要合并1这个节点下面所有红色节点为根的子树的和即5的大小3和6的大小3,加起来等于6,而1这个树本身的大小是11,所以对于整个sum[red]的增加量就是1为根的树的大小-6等于5,完了以后sum[red]=5+6=11等于1节点为根树的大小,再返回给1的祖先,同理我们从5和6节点那里得到他返回子树的大小也是通过同样类型的方式。这个可能就是所谓的虚树的应用吧!

代码:

 //Author: xiaowuga
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <ctime>
#include <map>
#include <bitset>
#include <cctype>
#define maxx INT_MAX
#define minn INT_MIN
#define inf 0x3f3f3f3f
#define mem(s,ch) memset(s,ch,sizeof(s))
#define da cout<<da<<endl
#define uoutput(a,i,l,r) for(int i=l;i<r;i++) if(i==l) cout<<a[i];else cout<<" "<<a[i];cout<<endl;
#define doutput(a,i,l,r) for(int i=r-1;i>=0;i--) if(i==r-1) cout<<a[i];else cout<<" "<<a[i];cout<<endl;
const long long N=+;
using namespace std;
typedef long long LL;
LL sum[N],sz[N],col[N],vis[N];
//sz[i]代表以i节点为根的子树大小
//col[i]代表的是i节点的颜色
//我们通过vis数组判断是否出现过某种颜色,以便统计出现了多少种颜色
//sum数组有点难理解,sum[i]表示当前i颜色的子树大小之和(在深搜过程中会值会改变。)
vector<int>p[N];
LL cut=,n;
void init(){//初始化
for(int i=;i<=n;i++){
p[i].clear();
sum[i]=sz[i]=cut=vis[i]=;
}
}
void dfs(int u,int pre){
sz[u]=;
LL s=sum[col[u]];
LL step=;
for(int i=;i<p[u].size();i++){
LL v=p[u][i];
if(v==pre) continue;
LL s=sum[col[u]];//这个点进栈前该点颜色的树的大小
dfs(v,u);
sz[u]+=sz[v];//加上所有子树的大小计算以u点为根的树的大小
LL qr=sum[col[u]]-s;//qr代表这个子树下面的同颜色孙树的大小
step+=qr;//合并所有子树中同样颜色的孙树大小
LL szv=sz[v]-qr;//这个子树与同u点颜色相同的孙树之间点的数量
cut=cut+szv*(szv-)/;//计算不存在颜色u的路径数
}
sum[col[u]]+=sz[u]-step;
}
int main() {
ios::sync_with_stdio(false);cin.tie();
int ca=;
while(cin>>n){
init();
LL ct=;
for(int i=;i<=n;i++) {
cin>>col[i];
if(!vis[col[i]]){ct++; vis[col[i]]=;}
}
for(int i=;i<n-;i++){
int x,y;
cin>>x>>y;
p[x].push_back(y);
p[y].push_back(x);
}
dfs(,);
for(int i=;i<=n;i++){
if(vis[i]&&i!=col[]){
LL szv=n-sum[i];
cut=cut+szv*(szv-)/;
}
}
LL ans=n*(n-)/*ct;
cout<<"Case #"<<++ca<<": "<<ans-cut<<endl;
}
return ;
}

2017 Multi-University Training Contest - Team 1—HDU6035的更多相关文章

  1. 2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】

    FFF at Valentine Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  2. 2017 Multi-University Training Contest - Team 9 1004&&HDU 6164 Dying Light【数学+模拟】

    Dying Light Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Tot ...

  3. 2017 Multi-University Training Contest - Team 9 1003&&HDU 6163 CSGO【计算几何】

    CSGO Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Subm ...

  4. 2017 Multi-University Training Contest - Team 9 1002&&HDU 6162 Ch’s gift【树链部分+线段树】

    Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

  5. 2017 Multi-University Training Contest - Team 9 1001&&HDU 6161 Big binary tree【树形dp+hash】

    Big binary tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)T ...

  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. 2017 Multi-University Training Contest - Team 1 1006&&HDU 6038 Function【DFS+数论】

    Function Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total ...

  8. 2017 Multi-University Training Contest - Team 1 1002&&HDU 6034 Balala Power!【字符串,贪心+排序】

    Balala Power! Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

  9. 2017 Multi-University Training Contest - Team 1 1011&&HDU 6043 KazaQ's Socks【规律题,数学,水】

    KazaQ's Socks Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)T ...

随机推荐

  1. [elk]logstash统计api访问失败率

    处理原始日志 日志从moogoo导出来的 { "mobile" : "13612345678", "isp" : "中国移动_广东 ...

  2. Leetcode[81]-Search for a Range

    Link: https://leetcode.com/problems/search-in-rotated-sorted-array-ii/ Given a sorted array of integ ...

  3. ng-class中的if else判断

    ng-class中的if else判断 来自于stackoverflow的一个问题,自己刚好用到,搬过来做个标记.原问题链接 在使用ng-class时,有些时候会碰到根据是否满足条件来设置元素的样式, ...

  4. Ubuntu下安装RabbbitVCS(图形化svn管理工具)- Ubuntu也有TortoiseSVN

    在Windows下用惯了TortoiseSVN这只小乌龟,到了Ubuntu下很不习惯命令行的SVN,于是经过一番寻找安装了RabbitVCS这款SVN图形化前端工具(官方网站:http://rabbi ...

  5. FreeRTOS 消息队列

    以下基础内容转载自安富莱电子: http://forum.armfly.com/forum.php 本章节为大家讲解 FreeRTOS 的一个重要的通信机制----消息队列,初学者要熟练掌握,因为消息 ...

  6. Makefile 11——支持头文件目录指定

    现在,是时候在对应目录放入对应文件了: /× foo.h */ #ifndef __FOO_H #define __FOO_H void foo(void) #endif/*__FOO_H*/ /* ...

  7. floyd算法&迪杰斯特拉算法

    ; k<=n; k++) ; i<=n; i++) ; j<=n; j++) { gra[i][j]=min(gra[i][j],gra[i][k]+gra[k][j]); } vo ...

  8. Centos 挂载NTFS格式的USB硬盘

    公司的一台服务器本身硬盘容量较小,要加一块2T的硬盘,用来做samba服务器,以下是挂载硬盘的主要记录: 这是服务器不认NTFS格式的情况:mount: unknown filesystem type ...

  9. QListView和QListWidget的区别

    QListView是基于Model,而QListWidget是基于Item.这是它们的本质区别. 往QListView中添加条目需借助QAbstractListModel: 如: MainWindow ...

  10. [转]第2台Tomcat端口变更失败解决办法

    原文链接:http://blog.csdn.net/preterhuman_peak/article/details/41803361 今天在服务器上部署了两个Tomcat.于是将其中一个的serve ...