题目链接: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. js获取地址栏传参

    地址:http://127.0.0.1:8082/prosperleedir/index.html?id=6666&name=prosper#prosper         Location{ ...

  2. 2019-02-10 扩展Python控制台实现中文反馈信息

    "中文编程"知乎专栏原文地址 参考了周蟒的实现, 运行效果如下: $ python3 解释器.py Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 ...

  3. 在Office应用中打开WPF窗体并且让子窗体显示在Office应用上

    在.NET主程序中,我们可以通过创建 ExcelApplication 对象来打开一个Excel应用程序,如果我们想在Excle里面再打开WPF窗口,问题就不那么简单了. 我们可以简单的实例化一个WP ...

  4. Linux tail 命令

    tail 命令可用于查看文件的内容,有一个常用的参数 -f 常用于查阅正在改变的日志文件. tail -f filename 会把 filename 文件里的最尾部的内容显示在屏幕上,并且不断刷新,只 ...

  5. scrollTo不起作用

    最近,我在HorizontalScrollview中使用scrollTo不起作用? ...... 以上省略N个字. 我只想说: 在使用scrollTo的时候,要先保证该HorizontalScroll ...

  6. 仿9GAG制作过程(五)

    有话要说: 在做完了数据展示功能之后,就想着完善整个APP.发现现在后台非常的混乱,有好多点都不具备,比方说:图片应该有略缩图和原图,段子.评论.点赞应该联动起来,段子应该有创建时间等. 于是就重新设 ...

  7. Android Activity生命周期图解

    Android activity的生命周期这一张图就够了. 验证结果: 值得注意的是从activity A--->activity B是先执行A的onPause然后走B的生命周期最后才走A的on ...

  8. Android远程桌面助手扩展之微信跳一跳辅助

    微信跳一跳的外挂辅助已是五花八门,万能的TB上也有了各种明码标价的代练.微信小程序游戏的火爆甚至带火了手游外挂产业.另一方面,跳一跳游戏也在不断更新,防止使用外挂刷高分.Android远程桌面助手支持 ...

  9. Android 使用Picasso加载网络图片等比例缩放

    在做android图片加载的时候,由于手机屏幕受限,很多大图加载过来的时候,我们要求等比例缩放,比如按照固定的宽度,等比例缩放高度,使得图片的尺寸比例得到相应的缩放,但图片没有变形.显然按照andro ...

  10. Android 性能优化之工具和优化点总结

    Android性能优化学习 最近公司主抓性能优化工作,借此春风也学习到了许多Android性能优化方面的知识.由于组内队友的给力,优化的成果也是比较喜人.同时也学习和实践了不少知识,特此记录. 1.性 ...