本题前面的操作别的博客里都有。难点在于颜色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. 使用cordova,使html5也能像IOS,Android那样可以 调取手机的相机拍照功能

    一,我们在使用html5的技术开发手机app时,并不能像IOS,Android那样可以调取手机原生的相机功能,这是我们就要借助一些插件来时实现. 二,安装Cordoba的相机插件 1.在文件目录下,使 ...

  2. leetcode-12双周赛-1244-力扣排行榜

    题目描述: class Leaderboard: def __init__(self): self.map = collections.Counter() def addScore(self, pla ...

  3. PHP中关于Phar的学习

    什么是phar 一个PHP程序往往是由多个文件组成的,如果能够集中为一个文件来分发和运行是很方便的.phar便应运而生.大概跟java的jar文件是差不多类似的.但是php的phar文件是可以由php ...

  4. java 后台 实现简单的验证码

    private int width =80;private int height=30;private Random r=new Random();private String fontnames[] ...

  5. 剑指offer——丑数(c++)

    题目描述只包含质因子2.3和5的数称作丑数(UglyNumber).例如6.8都是丑数,但14不是,因为它包含质因子7,习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 思路:1.逐个 ...

  6. Android API Levels 详解

    Android API Levels 当你开发你的Android应用程序时,了解该平台API变更管理的基本方法和概念是很有帮助的.同样的,知道API级别标识以及该标识如何保障你的应用与实际硬件设备相兼 ...

  7. switch type 类型判断

    golang 语言中 也有 类是 javascript 的 typeof 判断类型的 方法 比如 func (a interface{}){ //第一种 if inst,ok:=a.(TypeA);o ...

  8. Django+paramiko实现webshell

    说明 基于 python3.7 + django 2.2.3 实现的 django-webshell,支持颜色显示,支持 tab 命令补全,项目地址:https://github.com/leffss ...

  9. mysql怎样更改密码和用户名

    mysql怎样更改密码和用户名 更改密码(老版本): mysql -u root -p Enter password:*** mysql>use mysql; --选择数据库-- Databas ...

  10. 牛客网多校训练第八场A All one Matrix

    题目链接:https://ac.nowcoder.com/acm/contest/888/A 题意:求出有多少个不被包含的全1子矩阵 解题思路:首先对列做处理,维护每个位置向上1的个数,然后我们从最后 ...