首先,一棵子树究竟是白色满足Xi还是黑色满足Xi是无关紧要的,因为我们总可以翻转所有的节点来得到满足条件的解
对于每棵子树,某种颜色的权值和已经是固定的了,我们自然关注另一种颜色的权值和
可以想到dp[i][j]表示当前在考虑以i为根的子树,与根颜色不同的节点权值和是j且该子树内所有的Xi均满足能否实现
我们显然希望通过对子树背包来实现这一点
我们令dp2[i][j][k]表示当前考虑到第i个孩子,与根颜色相同的节点权值和是j,与根颜色不同的节点权值和是k能否实现
我们只要枚举当前孩子与根颜色不同的节点权值和,就可以实现转移
但这样的复杂度是
O(n3)
O
(
n
3
)
考虑减少状态,发现没有办法减少
考虑优化状态的表示
我们尝试考虑什么样的情况会导致impossible
对于当前的子树i,如果它的所有孩子中,不论怎么分配孩子的X是否对根产生贡献,两种颜色的权值和都大于Xi,那么就会出现impossible
我们发现,权值较小是没有关系的,因为我可以调整根的权值使其满足题意,但如果权值和大了就有麻烦
所以我们的目标应该是每一步最小化与根节点颜色不同的节点权值和
令dp[i]表示以i为根的子树,与根节点颜色不同的节点权值和最小是多少
仍然对子树背包转移
令dp2[i][j]表示考虑到第i个孩子,与根颜色相同的节点权值和是j的情况下,与根颜色不同的节点权值和最小是多少
转移是很简单的
dp[i]只要在dp2[cc][0~p[i]]之中选一个最小的就好,(cc是孩子个数)
总复杂度
O(n2)
O
(
n
2
)
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <utility>
#include <cctype>
#include <algorithm>
#include <bitset>
#include <set>
#include <map>
#include <vector>
#include <queue>
#include <deque>
#include <stack>
#include <cmath>
#define LL long long
#define LB long double
#define x first
#define y second
#define Pair pair<int,int>
#define pb push_back
#define pf push_front
#define mp make_pair
#define LOWBIT(x) x & (-x)
using namespace std;
const int MOD=1e9+7;
const LL LINF=2e17;
const int INF=1e9;
const int magic=348;
const long double eps=1e-15;
const double pi=3.14159265;
inline int getint()
{
char ch;int res;bool f;
while (!isdigit(ch=getchar()) && ch!='-') {}
if (ch=='-') f=false,res=0; else f=true,res=ch-'0';
while (isdigit(ch=getchar())) res=res*10+ch-'0';
return f?res:-res;
}
int p[1048],n;
int dp[1048],son[1048][5048];
int head[100048],nxt[200048],to[200048],tot=1;
inline void addedge(int s,int t)
{
to[++tot]=t;nxt[tot]=head[s];head[s]=tot;
}
inline void dfs(int cur)
{
int i,j,y,cc=0;
for (i=head[cur];i;i=nxt[i]) dfs(to[i]);
for (i=head[cur];i;i=nxt[i])
{
y=to[i];cc++;
for (j=0;j<=5000;j++) son[cc][j]=INF;
for (j=0;j<=5000;j++)
{
if (j>=p[y]) son[cc][j]=min(son[cc][j],son[cc-1][j-p[y]]+dp[y]);
if (j>=dp[y]) son[cc][j]=min(son[cc][j],son[cc-1][j-dp[y]]+p[y]);
}
}
dp[cur]=INF;
for (i=0;i<=p[cur];i++) dp[cur]=min(dp[cur],son[cc][i]);
}
int main ()
{
int i,x;n=getint();
for (i=2;i<=n;i++) x=getint(),addedge(x,i);
for (i=1;i<=n;i++) p[i]=getint();
dfs(1);
if (dp[1]<INF) printf("POSSIBLE\n"); else printf("IMPOSSIBLE\n");
return 0;
}