回滚树形dp(按dfs序dp)——hdu6035
本题前面的操作别的博客里都有。难点在于颜色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的更多相关文章
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- 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 ...
- HDU 1501 Zipper(DP,DFS)
意甲冠军 是否可以由串来推断a,b字符不改变其相对为了获取字符串的组合c 本题有两种解法 DP或者DFS 考虑DP 令d[i][j]表示是否能有a的前i个字符和b的前j个字符组合得到c的前i+j ...
- 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 ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...
- hdu_5293_Tree chain problem(DFS序+树形DP+LCA)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=5293 被这题打蹦了,看着题解写的,很是爆炸,确实想不到,我用的DFS序+LCA+树形DP,当然也可以写 ...
- HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca
Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...
- 【BZOJ2286】消耗战(虚树,DFS序,树形DP)
题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权. 共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价. ...
随机推荐
- web.xml中配置——解决post乱码
<!-- 解决post乱码 --> <filter> <filter-name>CharacterEncodingFilter</filter-name> ...
- rest framework之限流组件
一.自定义限流 限流组件又叫做频率组件,用于控制客户端可以对API进行的请求频率,比如说1分钟访问3次,如果在1分钟内超过3次就对客户端进行限制. 1.自定义限流 假设现在对一个API访问,在30s内 ...
- vue 初始化rem
在assets => js => rem.js export default { init () { let sw = document.documentElement.clientWid ...
- Nginx---文档(从入门到精通)
very good http://tengine.taobao.org/book/index.html
- 思维构造+匹配——cf1199E
直接枚举每条边,如果边加到图中后还是个匹配图,就直接加,反之就不加 这样加完所有边后,剩下的点必定可以组成一个独立集:因为如果剩下的点中还有互相匹配的,那么这对点应该在加边时就被算到匹配图中 所以要么 ...
- DNS域名服务器的搭建
父域的DNS(svr7): 可以解析父域名下保存的域名地址,即解析.tedu.cn下的域名 一.安装软件包bind.bind-chroot bind是DNS解析服务需要用到的服务软件包,bind- ...
- 【转】/bin/bash^M: bad interpreter: 没有那个文件或目录
运行脚本时出现了这样一个错误,打开之后并没有找到所谓的^M,查了之后才知道原来是文件格式的问题,也就是linux和windows之间的不完全兼容,解决的方法有两种: 1 如果os中已经安装dos2un ...
- Linux内核代码布局
上文参考:http://www.cnblogs.com/long123king/p/3545991.html 先分析一下linker script的语法. #ifdef CONFIG_X86_32#d ...
- NIO 源码分析(03) 从 BIO 到 NIO
目录 一.NIO 三大组件 Channels.Buffers.Selectors 1.1 Channel 和 Buffer 1.2 Selector 1.3 Linux IO 和 NIO 编程的区别 ...
- linux网卡驱动更新方法
kernel: eth0: igb_reset_task: Reset adapter解决方法 1. LVS集群web项目,运行大概一个月左右出现访问慢的情况,查询mysql服务器时/var/log/ ...