题目链接:http://codeforces.com/contest/461/problem/B

题目大意:

  给定一课树,树上的节点有黑的也有白的,有这样一种分割树的方案,分割后每个子图只含有一个黑色节点,问这样的分割方案一共有多少种?

分析:

先定义3个函数(为了之后说起来方便):

  设A(x) = 在以顶点x为根的子树中,所有满足使x所在子图不含黑色顶点,其余子图只含有1个黑色顶点的分割方案种数 。
  设B(x) = 在以顶点x为根的子树中,所有满足每个子图只含有1个黑色顶点的分割方案种数 。
  设C(x) = 在以顶点x为根的子树中,所有满足使x所在子图只含有1个黑色顶点,其余子图只含有1个黑色顶点的分割方案种数 。
  显然B(x) = C(x)
  首先我们关注某一课子树的根节点,不妨设为rt,有2种情况:
  不妨设rt有a个黑色的孩子节点,b个白色的孩子节点,rt的第i个黑色节点表示为rtBi,白色节点表示为rtWi,rt的第i个孩子节点表示为soni
1 : color[rt] == WHITE
  初始条件下B(rt) = 0
  在这种情况下,rt与每个孩子节点都有相连与不相连2种策略,对于soni,不相连的贡献自然是B(soni),而相连的贡献就不是独立的了,很可能有跨越根节点到其他子树的方案,也就是说,对于每一棵子树,都要和其他每一棵子树有深入交流。
  我们可以考虑增而治之,设rtSonsi为以rt为根节点,只拥有前i个孩子节点的树,A(rt),B(rt),C(rt)为相应数值,初始状态为A(rt) = 1,B(rt) = 0,C(rt) = 0,我们只要考虑soni+1加入时,A(rt),B(rt),C(rt)会如何变化,当子树全部加入时,就算完了。这里有2种情况:
  (1)与soni+1相连:B(rt)  = C(rt) = A(rt) * C(soni+1) + C(rt) * A(soni+1)
                                    A(rt) = A(rt) * A(soni+1)
  (2)与soni+1不相连:B(rt)  = C(rt) = C(rt) * C(soni+1)
                                        A(rt) = A(rt) * C(soni+1)
  于是总变化为:B(rt)  = C(rt) = A(rt) * C(soni+1) + C(rt) * [A(soni+1) + C(soni+1)]

                           A(rt) = A(rt) * [A(soni+1) + C(soni+1)]
 
 

2:color[rt] == BLACK
  初始条件下B(rt) = 1,自己自身算一个
  在这种情况下,rt一定不能与黑色的孩子节点相连,而对于白色的孩子节点,有相连与不相连两种选择。
  同样增而治之,设rtSonsi为以rt为根节点,只拥有前i个孩子节点的树,A(rt),B(rt),C(rt)为相应数值,初始状态为A(rt) = 0,B(rt) = 1,C(rt) = 1并且A(rt)恒等于0,我们只要考虑soni+1加入时,A(rt),B(rt),C(rt)会如何变化,当子树全部加入时,就算完了。这里有3种情况:
  (1)soni+1为白色节点&&与soni+1相连:B(rt)  = C(rt) = C(rt) * A(soni+1)
  (2)soni+1为白色节点&&与soni+1不相连:B(rt)  = C(rt) = C(rt) * C(soni+1)
  (3)soni+1为黑色节点(和2是同一种情况):B(rt)  = C(rt) = C(rt) * C(soni+1)
  于是总变化为:B(rt)  = C(rt) = C(rt) * [A(soni+1) + C(soni+1)]

 
一个优化:对于color[rt] == BLACK的情况,如果我们把rt看成是白色的,然后照此计算出A(rt),B(rt),C(rt),那么以rt为根节点的子树的真实方案数,不就是A(rt)吗?这样的话就没有必要分情况了,在最后加个判断即可。

 

代码如下:

 #include <bits/stdc++.h>
using namespace std; #define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define rFor(i,t,s) for (int i = (t); i >= (s); --i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)
#define rforeach(i,c) for (__typeof(c.rbegin()) i = c.rbegin(); i != c.rend(); ++i) #define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl #define LOWBIT(x) ((x)&(-x)) #define ALL(x) x.begin(),x.end()
#define INS(x) inserter(x,x.begin()) #define ms0(a) memset(a,0,sizeof(a))
#define msI(a) memset(a,inf,sizeof(a))
#define msM(a) memset(a,-1,sizeof(a)) #define pii pair<int,int>
#define piii pair<pair<int,int>,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second inline int gc(){
static const int BUF = 1e7;
static char buf[BUF], *bg = buf + BUF, *ed = bg; if(bg == ed) fread(bg = buf, , BUF, stdin);
return *bg++;
} inline int ri(){
int x = , f = , c = gc();
for(; c<||c>; f = c=='-'?-:f, c=gc());
for(; c>&&c<; x = x* + c - , c=gc());
return x*f;
} typedef long long LL;
typedef unsigned long long uLL;
const int inf = 1e9 + ;
const LL mod = 1e9 + ;
const int maxN = 1e5 + ; struct Node{
vector< int > next;
}; int n, ans; /*
设A(x) = 在以顶点x为根的子树中,所有满足使x所在子图不含黑色顶点,其余子图只含有1个黑色顶点的分割方案种数
设B(x) = 在以顶点x为根的子树中,所有满足每个子图只含有1个黑色顶点的分割方案种数
设C(x) = 在以顶点x为根的子树中,所有满足使x所在子图只含有1个黑色顶点,其余子图只含有1个黑色顶点的分割方案种数
则有:
dp[v][0] = A(v) + B(v)
dp[v][1] = B(v)
C(v) = B(v)
The answer is dp[0][1].
*/
LL dp[maxN][];
Node nodes[maxN];
int color[maxN]; void dfs(int x) {
// 默认顶点x为白色
dp[x][] = ;
dp[x][] = ; foreach(i, nodes[x].next) {
dfs(*i);
// dp[*i][0] 包含 A(*i) 和 C(*i),对于A(*i),令其与C(x)相连
// 而对于C(*i),令其与C(x)分断
dp[x][] = (dp[x][] * dp[*i][]) % mod;
// dp[x][0] 包含 A(x),令其与C(*i)相连
dp[x][] = (dp[x][] + dp[x][] * dp[*i][]) % mod;
// 此时dp[x][0] = A(x)
// dp[x][0] * dp[*i][0] = A(x)*A(*i) + A(x)*C(*i)
// 依次是连接新子树的A(*i)部分和断掉新子树的C(*i)部分,两这都可以保证dp[x][0]更新后还是A(x)
dp[x][] = (dp[x][] * dp[*i][]) % mod;
} if(color[x] == ) dp[x][] = dp[x][]; // 当根节点为黑色时,A(x)实际上是C(x),而真正的A(x) = 0
else dp[x][] = (dp[x][] + dp[x][]) % mod; // 此时 dp[x][0] = A(x) + C(x)
} int main(){
while(cin >> n) {
rep(i, n) nodes[i].next.clear();
For(i, , n-) {
int t;
cin >> t;
// 根据题目要求,并不需要加反向边
nodes[t].next.push_back(i);
}
rep(i, n) cin >> color[i]; dfs(); cout << dp[][] <<endl;
}
return ;
}

CodeForces 461B Appleman and T的更多相关文章

  1. Codeforces 461B Appleman and Tree(木dp)

    题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k ...

  2. Codeforces 461B. Appleman and Tree[树形DP 方案数]

    B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  3. Codeforces 461B Appleman and Tree

    http://codeforces.com/problemset/problem/461/B 思路:dp,dp[i][0]代表这个联通块没有黑点的方案数,dp[i][1]代表有一个黑点的方案数 转移: ...

  4. Codeforces 461B Appleman and Tree:Tree dp

    题目链接:http://codeforces.com/problemset/problem/461/B 题意: 给你一棵树(编号从0到n-1,0为根节点),每个节点有黑白两种颜色,其中黑色节点有k+1 ...

  5. Codeforces 461B - Appleman and Tree 树状DP

    一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都仅仅有1个黑色节点,共同拥有多少种划分方案. 个人感觉这题比較难. 如果dp(i,0..1)代表的是以i为根节点的子树种有0 ...

  6. CodeForces 462B Appleman and Card Game(贪心)

    题目链接:http://codeforces.com/problemset/problem/462/B Appleman has n cards. Each card has an uppercase ...

  7. codeforces 462C Appleman and Toastman 解题报告

    题目链接:http://codeforces.com/problemset/problem/461/A 题目意思:给出一群由 n 个数组成的集合你,依次循环执行两种操作: (1)每次Toastman得 ...

  8. CF 461B Appleman and Tree 树形DP

    Appleman has a tree with n vertices. Some of the vertices (at least one) are colored black and other ...

  9. Codeforces 263B. Appleman and Card Game

    B. Appleman and Card Game time limit per test  1 second memory limit per test  256 megabytes input  ...

随机推荐

  1. JSON字符串反序列化成对象_部分属性值反序列化失败

    简介:本人在开发webapi接口时遇到了:一个复杂的Json字符串在反序列化为对象时报,无法发序列化其中的一个属性对象? 使用方法: InternalRecommendRequestFormModel ...

  2. 用node.js express设置路径后 子路径下的页面访问静态资源路径出问题

    在routes/news_mian.js 设置了访问news_main.html 的路径 '/',通知设置一个访问news-page.html的子路径'/newspage'子路径.但是在访问loacl ...

  3. 面试题之(HTTP协议)【转】

    转自:http://www.cnblogs.com/ranyonsue/p/5984001.html HTTP简介 HTTP协议是Hyper Text Transfer Protocol(超文本传输协 ...

  4. Spring(一)JdbcTemplate的环境搭建

    1.建立一个项目,导入jar包(ioc aop dao 连接池 数据库驱动包)拷贝Spring容器对应的配置文件到src下 2.在配置文件中引入外部属性文件 3.配置数据源 4.配置JdbcTempl ...

  5. XSS Challenges

    平台: http://www.zixem.altervista.org/XSS/ level1: Payload: http://www.zixem.altervista.org/XSS/1.php? ...

  6. Dynamics 365使用代码发送邮件给指定邮箱地址

    摘要: 微软动态CRM专家罗勇 ,回复303或者20190213可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!我的网站是 www.luoyong.me . 当然,首先要 ...

  7. 《Odoo开发指南》精选分享—第1章-开始使用Odoo开发(1)

    引言 在进入Odoo开发之前,我们需要建立我们的开发环境,并学习它的基本管理任务. 在本章中,我们将学习如何设置工作环境,在这里我们将构建我们的Odoo应用程序.我们将学习如何设置Debian或Ubu ...

  8. SQL Server实际执行计划COST"欺骗"案例

    有个系统,昨天Support人员发布了相关升级脚本后,今天发现系统中有个功能不能正常使用了,直接报超时了(Timeout expired)的错误.定位到相关相关存储过程后,然后在优化分析的过程中,又遇 ...

  9. linux备份还原命令

    使用范围:1.可以作为系统还原点,还原到备份时的状态 2.系统完全损坏后无法启动,通过引导盘恢复 一.备份还原系统命令 方法一: 备份:tar cvpzf backup.tgz --exclude=/ ...

  10. Linux 访问控制列表(access control list)

    简介 随着应用的发展,传统的linux文件系统权限控制无法适应复杂的控制需求,而ACL的出现,则是为了扩展linux的文件权限控制,以实现更为复杂的权限控制需求.其可以针对任意的用户和用户组进行权限分 ...