本题前面的操作别的博客里都有。难点在于颜色ci的贡献,如何一次dfs求出答案

先来考虑如何在一次dfs中单独对颜色i进行计算

  用遍历dfs序的方式,在深搜过程中,碰到带有颜色 i 的点 u,u每个颜色不为i的子节点v都会贡献一个联通块,

  v的贡献的联通块大小是size[v]-sum{v中层次最高的以颜色i的结点为根的子树大小}

  那我们要先求出v中层次最高的以颜色i的结点为根的子树大小,所以用sum表示目前为止颜色i的所有子树的大小,用last存下v进入dfs前的sum,即不算v下颜色i的子树时的sum

  到v中去dfs,然后把这些子树的大小加到sum中

  当遍历完v的所有子树后,我们会发现 sum-last 就是v下层次最高的以颜色i的结点为根的子树大小的总和

  那么v贡献出的联通块大小就是 k = size[v]-(sum-last)

  然后去u的下一棵子树v'进行同样的操作,直到遍历完u的所有子树,此时sum已经变成了到u为止(不包含u)的以颜色i为根的子树大小之和

  为了计算u的颜色为i的祖先,需要把u也并入sum里,那么只需要在sum里加入u自己,再加上所有v贡献的联通块即可

  现在已经维护完所有的信息,可以推出u的dfs,往上回滚求出u的祖先结点的信息

再来考虑如何在一次dfs中对所有出现的颜色进行计算,

  我们可以在上面的递归中发现,每中颜色在求贡献只用到了size[],还有每种颜色对应的sum,那么用sum[c]数组来维护颜色c代表的sum即可,就可以在一次dfs中维护多种颜色的贡献

本题和虚树有些类似的地方,首先把每种颜色当成是一个询问,就类似虚树的询问了

然后是回滚dfs的过程,自叶子往上求(其实是按照dfs序)的方式:在初次碰到u时记录进入dfs前的状态,然后dfs处理完其所有子节点的状态后再来计算u的状态

#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define maxn 200005
#define ll long long ll ans,color[maxn],size[maxn],sum[maxn];
vector<int>G[maxn]; void dfs1(int u,int pre){
size[u]=;
for(int i=;i<G[u].size();i++){
int v=G[u][i];
if(v==pre)continue;
dfs1(v,u);
size[u]+=size[v];
}
} //这个树形dp最重要的是理解sum[]数组的含义,sum[x]的更新像虚树的加边一样是自叶子节点往上回滚的
void dfs2(int u,int pre){
ll other=;//other表示为size[u]减去u下所有最高的以color[u]为根的大小
for(int i=;i<G[u].size();i++){
int v=G[u][i];
if(v==pre)continue;
ll last=sum[color[u]];//记录前前面子树里颜色u的子树(虚树)里的值
dfs2(v,u);
ll diff=sum[color[u]]-last;//v的子树里颜色为color[u]的个数
//v树下不包含color[u]的联通块的大小
ans+=(size[v]-diff-)*(size[v]-diff)/;
other+=size[v]-diff;
}
sum[color[u]]+=other+;//+1是因为u本身也是color[u]
}
int f[maxn],tot;
int main(){
ll n,t=;
while(cin>>n){
++t;
for(int i=;i<=n;i++)G[i].clear();
memset(f,,sizeof f);
tot=; for(int i=;i<=n;i++){
scanf("%d",&color[i]);
f[color[i]]=;
}
for(int i=;i<=n;i++)tot+=f[i];
for(int i=;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
} if(tot==){
printf("Case #%d: %lld\n",t,n*(n-)/);
continue;
} memset(size,,sizeof size);
memset(sum,,sizeof sum); ans=;
dfs1(,);dfs2(,);
for(int i=;i<=n;i++)
if(f[i])
ans+=(n-sum[i])*(n-sum[i]-)/;
ll tmp=(n-)*n/*tot;
printf("Case #%d: %lld\n",t,tmp-ans); }
}

回滚树形dp(按dfs序dp)——hdu6035的更多相关文章

  1. BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序

    https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...

  2. Codeforces Round #358 (Div. 2) A B C 水 水 dfs序+dp

    A. Alyona and Numbers time limit per test 1 second memory limit per test 256 megabytes input standar ...

  3. HDU 1501 Zipper(DP,DFS)

    意甲冠军  是否可以由串来推断a,b字符不改变其相对为了获取字符串的组合c 本题有两种解法  DP或者DFS 考虑DP  令d[i][j]表示是否能有a的前i个字符和b的前j个字符组合得到c的前i+j ...

  4. hdu3974 Assign the task dfs序+线段树

    There is a company that has N employees(numbered from 1 to N),every employee in the company has a im ...

  5. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  6. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  7. hdu_5293_Tree chain problem(DFS序+树形DP+LCA)

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5293 被这题打蹦了,看着题解写的,很是爆炸,确实想不到,我用的DFS序+LCA+树形DP,当然也可以写 ...

  8. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

  9. 【BZOJ2286】消耗战(虚树,DFS序,树形DP)

    题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...

随机推荐

  1. web.xml中配置——解决post乱码

    <!-- 解决post乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> ...

  2. rest framework之限流组件

    一.自定义限流 限流组件又叫做频率组件,用于控制客户端可以对API进行的请求频率,比如说1分钟访问3次,如果在1分钟内超过3次就对客户端进行限制. 1.自定义限流 假设现在对一个API访问,在30s内 ...

  3. vue 初始化rem

    在assets => js => rem.js export default { init () { let sw = document.documentElement.clientWid ...

  4. Nginx---文档(从入门到精通)

    very good http://tengine.taobao.org/book/index.html

  5. 思维构造+匹配——cf1199E

    直接枚举每条边,如果边加到图中后还是个匹配图,就直接加,反之就不加 这样加完所有边后,剩下的点必定可以组成一个独立集:因为如果剩下的点中还有互相匹配的,那么这对点应该在加边时就被算到匹配图中 所以要么 ...

  6. DNS域名服务器的搭建

    父域的DNS(svr7): 可以解析父域名下保存的域名地址,即解析.tedu.cn下的域名 一.安装软件包bind.bind-chroot   bind是DNS解析服务需要用到的服务软件包,bind- ...

  7. 【转】/bin/bash^M: bad interpreter: 没有那个文件或目录

    运行脚本时出现了这样一个错误,打开之后并没有找到所谓的^M,查了之后才知道原来是文件格式的问题,也就是linux和windows之间的不完全兼容,解决的方法有两种: 1 如果os中已经安装dos2un ...

  8. Linux内核代码布局

    上文参考:http://www.cnblogs.com/long123king/p/3545991.html 先分析一下linker script的语法. #ifdef CONFIG_X86_32#d ...

  9. NIO 源码分析(03) 从 BIO 到 NIO

    目录 一.NIO 三大组件 Channels.Buffers.Selectors 1.1 Channel 和 Buffer 1.2 Selector 1.3 Linux IO 和 NIO 编程的区别 ...

  10. linux网卡驱动更新方法

    kernel: eth0: igb_reset_task: Reset adapter解决方法 1. LVS集群web项目,运行大概一个月左右出现访问慢的情况,查询mysql服务器时/var/log/ ...