Codeforces 461B - Appleman and Tree 树状DP
一棵树上有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的更多相关文章
- Codeforces 461B Appleman and Tree(木dp)
题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k ...
- poj2486--Apple Tree(树状dp)
Apple Tree Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 7789 Accepted: 2606 Descri ...
- Codeforces 461B. Appleman and Tree[树形DP 方案数]
B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- Codeforces 461B Appleman and Tree
http://codeforces.com/problemset/problem/461/B 思路:dp,dp[i][0]代表这个联通块没有黑点的方案数,dp[i][1]代表有一个黑点的方案数 转移: ...
- CodeForces - 396C On Changing Tree(树状数组)
题目大意 给定一棵以1为根的树,初始时所有点为0 给出树的方式是从节点2开始给出每一个点的父亲 然后是 $m$ 次操作,分为两种 $1 v,k,x$ 表示在以v为根的子树中的每一个点上添加 $x-i* ...
- Codeforces 461B Appleman and Tree:Tree dp
题目链接:http://codeforces.com/problemset/problem/461/B 题意: 给你一棵树(编号从0到n-1,0为根节点),每个节点有黑白两种颜色,其中黑色节点有k+1 ...
- POJ 2486 Apple Tree [树状DP]
题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1.一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果. 思路:这里给出数组的定义: dp[0][x][j] 为从结点 ...
- CodeForces 160D - Distance in Tree 树型DP
题目给了512MB的空间....用dp[k][i]代表以k为起点...往下面走(走直的不打岔)i步能有多少方案....在更新dp[k][i]过程中同时统计答案.. Program: #include& ...
- Codeforces 161D Distance in Tree(树型DP)
题目链接 Distance in Tree $k <= 500$ 这个条件十分重要. 设$f[i][j]$为以$i$为子树,所有后代中相对深度为$j$的结点个数. 状态转移的时候,一个结点的信息 ...
随机推荐
- linux内核中send与recv函数详解
Linux send与recv函数详解 1.简介 #include <sys/socket.h> ssize_t recv(int sockfd, void *buff, size_t n ...
- oncreate 测量尺寸
在android中,在oncreate里面只是将布局信息设置好,并没有进行布局,因此是没法进行测量view或者屏幕的长高,可以通过下面的observer来观察,当view布局完成之后会回调下面的两个接 ...
- 来自中油瑞飞的SQL笔试题20131202
1.有三张表,用户表,用户角色表,角色表, 使用sql显示如下内容: 用户ID,用户名,超级管理员,录入员,会计 也就是角色用逗号分隔. 解: 1.填充数据到表User select * from [ ...
- spring 整合redis
用的是最新的jedis-2.6.2.jar这个包,这个和以前的有点不同.还需要添加spring-data-redis-1.2.1.RELEASE.jar和commons-pool2-2.3.jar. ...
- Winfrom 文本框回车进入下一个个单元格(TextBox)
1.重写方法 OnShown protected override void OnShown(EventArgs e) { base.OnShown(e); foreach (Control ct i ...
- [置顶] 无名管道的C++封装
xpipe-无名管道的C++封装类 无名管道的C++封装类,用于父子进程进行通信 基础介绍 unix下一切皆文件,管道也不例外.无名管道pipe定义在<unistd.h>中. #inclu ...
- webdynpro 调用应用程序做跳转
1.是调用指的是调用生成应用程序,非webdynpro组件程序, 如下: 1)调用页面,并传值 METHOD get_zgmtpage . DATA:lw_application_name TYPE ...
- Servlet的学习之Session(5)
在上一篇中我们介绍了如果使用Session来做一个简单的用户登录案例,在本篇中我们继续使用Session技术来做一个防止表单重复提交的案例. 这是一个很重要的知识点,在很多框架中都有防止表单重复提交的 ...
- jquery控制动态生成的gridview中多列checkbox的全选反选及自动判断是否全选状态
动态生成的Gridview的前台html代码如下: <table class="usertableborder" cellspacing="0" ...
- 选择屏幕中的下拉框和dialog中下拉框设计
REPORT YTEST014. PARAMETERS: auart LIKE vapma-auart AS LISTBOX VISIBLE LENGTH 6. AT SELECTION-SC ...