一棵树上有K个黑色节点,剩余节点都为白色,将其划分成K个子树,使得每棵树上都仅仅有1个黑色节点,共同拥有多少种划分方案。

个人感觉这题比較难。

如果dp(i,0..1)代表的是以i为根节点的子树种有0..1个黑色节点的划分方案数。

当节点i为白色时。对于它的每一个孩子的节点处理:

求dp(i, 0)时有:

1,将该节点与孩子节点相连,但要保证孩子节点所在的子树种没有黑色节点;

2,将该节点不与该孩子节点相连。则该孩子节点要保证所在子树种有黑色节点;

即dp(i, 0) = π(dp(j,0 ) + dp(j, 1)) 。当中j为i的孩子节点

求dp(i,1)时有:

将该节点与当中每一个孩子节点中的一个相连,而且保证该孩子节点所在子树中有1个黑色节点(所以共同拥有K种情况,K为该节点的孩子数)。而且对于剩下的节点能够选择连也能够选择不连。假设连接。则保证该子节点所在子树中没有黑色,假设不连。则要保证有黑色。所以对于剩下的每一个

子节点的处理方案书有dp(j,0) + dp(j,1)个。然后将每一个孩子处理的方案书相乘就可以,最后将全部的方案相加就可以。

当节点i为黑色的时候,求dp(i, 0) 肯定是0;

求dp(i, 1)时对于i的每一个子节点也是有两种选择,连或者不连,假设连接。则保证该子节点所在子树中没有黑色,假设不连,则要保证有黑色,即对于每一个子节点的处理数共同拥有

dp(j, 0) + dp(j, 1)个,然后将每一个孩子处理的方案数相乘。

终于dp(0,1)即为答案。这里如果0节点为根节点。

过程中能够加个小小的优化,当一个子节点所在的整棵子树中若没有黑色节点,那么该节点肯定与其父节点相连,所以计算时能够不考虑该节点。

#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include <vector> using namespace std;
//int values[500001];
//long long sums[500001];
#define MODVALUE 1000000007
#define MOD(x) if((x) > MODVALUE) x %= MODVALUE; struct Edge
{
int to;
int i;
int totalcolor;
Edge()
{
totalcolor = 0;
}
}; int compp(const void* a1, const void* a2)
{
return *((int*)a2) - *((int*)a1);
} vector<Edge> G[100001];
int Color[100001];
long long res[100001][2];
//int TMP[100001];
bool Visited[100001]; void AddEdge(int from, int to)
{
Edge edge;
edge.to = to; edge.i = G[to].size();
G[from].push_back(edge);
edge.to = from; edge.i = G[from].size() - 1;
G[to].push_back(edge); } int CountColor(int node)
{
Visited[node] = true;
int count = 0;
if (Color[node])
{
count = 1;
}
for (int i = 0; i < G[node].size();i++)
{
Edge& edge = G[node][i];
if (!Visited[edge.to])
{
edge.totalcolor = CountColor(edge.to);
count += edge.totalcolor;
} }
return count;
} void GetAns(int node)
{
Visited[node] = true;
long long ans = 1;
int countofcolor = 0;
vector<int> TMP;
for (int i = 0; i < G[node].size(); i++)
{
Edge& edge = G[node][i];
if (Visited[edge.to])
{
continue;
}
//TMP[countofcolor++] = i;
GetAns(edge.to);
if (edge.totalcolor)
{
TMP.push_back(i);
countofcolor++;
//TMP[countofcolor++] = i;
}
}
res[node][0] = 0;
res[node][1] = 0; long long tmp1 = 1;
long long tmp0 = 1;
if (!Color[node])
{
tmp1 = 0;
}
for (int i = 0; i < countofcolor; i++)
{ if (Color[node])
{
Edge& edge = G[node][TMP[i]];
tmp1 *= (res[edge.to][1] + res[edge.to][0]);
MOD(tmp1);
tmp0 = 0;
}
else
{
Edge& edge1 = G[node][TMP[i]];
tmp0 *= (res[edge1.to][1] + res[edge1.to][0]);
MOD(tmp0);
long long tmp3 = 1;
for (int j = 0; j < countofcolor; j++)
{
Edge& edge = G[node][TMP[j]];
if (i == j)
{
tmp3 *= res[edge.to][1];
MOD(tmp3);
}
else
{
tmp3 *= (res[edge.to][1] + res[edge.to][0]);
MOD(tmp3);
} }
tmp1 += tmp3; } if (i == countofcolor - 1)
{
res[node][0] += tmp0;
res[node][1] += tmp1;
MOD(res[node][0]);
MOD(res[node][1]);
} }
if (countofcolor == 0)
{
res[node][0] = Color[node] ? 0 : 1;
res[node][1] = Color[node] ? 1 : 0;
}
} int main()
{
#ifdef _DEBUG
freopen("e:\\in.txt", "r", stdin);
#endif // _DEBUG
int n;
scanf("%d", &n);
for (int i = 0; i < n - 1; i++)
{
int value;
scanf("%d", &value);
AddEdge(i + 1, value);
}
for (int i = 0; i < n; i++)
{
int value;
scanf("%d", &value);
Color[i] = value;
}
memset(Visited, 0, sizeof(Visited));
CountColor(0);
memset(Visited, 0, sizeof(Visited));
GetAns(0);
printf("%I64d\n", res[0][1]);
return 0;
}

Codeforces 461B - Appleman and Tree 树状DP的更多相关文章

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

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

  2. poj2486--Apple Tree(树状dp)

    Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 7789   Accepted: 2606 Descri ...

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

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

  4. Codeforces 461B Appleman and Tree

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

  5. CodeForces - 396C On Changing Tree(树状数组)

    题目大意 给定一棵以1为根的树,初始时所有点为0 给出树的方式是从节点2开始给出每一个点的父亲 然后是 $m$ 次操作,分为两种 $1 v,k,x$ 表示在以v为根的子树中的每一个点上添加 $x-i* ...

  6. Codeforces 461B Appleman and Tree:Tree dp

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

  7. POJ 2486 Apple Tree [树状DP]

    题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1.一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果. 思路:这里给出数组的定义: dp[0][x][j] 为从结点 ...

  8. CodeForces 160D - Distance in Tree 树型DP

    题目给了512MB的空间....用dp[k][i]代表以k为起点...往下面走(走直的不打岔)i步能有多少方案....在更新dp[k][i]过程中同时统计答案.. Program: #include& ...

  9. Codeforces 161D Distance in Tree(树型DP)

    题目链接 Distance in Tree $k <= 500$ 这个条件十分重要. 设$f[i][j]$为以$i$为子树,所有后代中相对深度为$j$的结点个数. 状态转移的时候,一个结点的信息 ...

随机推荐

  1. Last_IO_Errno: 1236 Last_IO_Error: Got fatal error 1236 from master when reading data from binary lo

    mysql> show slave status\G *************************** 1. row ***************************         ...

  2. 基于visual Studio2013解决C语言竞赛题之1051数的顺序

       题目 解决代码及点评 /* 功能:自然数N一般写成如下形式: N=d[k]d[k-1]d[1] (d[1]-d[k] 均是十进制数字) 如果d[i+1]>d[i] (i=k-1 ...

  3. lastIndexOf方法——获取字符最后的索引

    1.2.20 lastIndexOf方法——获取字符最后的索引 2013-08-29 14:55:18     我来说两句 收藏    我要投稿   本文所属图书 > Java程序开发参考手册 ...

  4. 基于visual Studio2013解决面试题之0302链表中找倒数k项节点

     题目

  5. boost.asio系列——socket编程

    asio的主要用途还是用于socket编程,本文就以一个tcp的daytimer服务为例简单的演示一下如何实现同步和异步的tcp socket编程. 客户端 客户端的代码如下: #include &l ...

  6. Eclipse代码字体、颜色美化,更改字体大小、颜色

    先看效果: 感觉如何,是否比你的eclipse编辑器显示的代码要漂亮简洁呢?呵呵.这个是我原来ADT Eclipse的效果,现在去下居然更新掉了,找不到了.于是我就参照我原来的配置对这个新的Eclip ...

  7. 强算KMeans聚类算法演示器

    这些天做C#实验以及这个KMeans算法演示器,学了一下openGL,感觉有待加强. //Point.h /* Point 结构体定义及实现 结构体重载了2个运算符: 1.== //推断两个Point ...

  8. 理想非常丰满,现实非常骨感——致WiFi通话

    WiFi通话一词,近来火热,国外,iOS 8系统測试版新增WiFi通话功能,英国运营商也着手WiFi免费通话,国内也没落下,阿里发布的170资费方案中就包含WiFi免费通话. 近日,据外媒报道,在美国 ...

  9. STM8S 串口应用 UART2 STM8S105

    //少说话.多做事,下面是我验证过没有问题的串口发送接受数据 //使用MCU stm8s105c6 UART2 //初始化时调用: GPIO_DeInit(GPIOD); /* Configure P ...

  10. 怎样将baidu地图中的baidu logo 去掉

    今天我的老大问我是不是能够将baidumap 的js版中baidu logo 去掉. 我上网查询一下,有各种方法.比方将相应的logo div remove hide 等等,这些都是须要JS 函数触发 ...