链接:AT3536
(翻译在讨论中有)
题解
对于一个点
,若其为黑色,则以
为根的字数中黑色总和为
,白色总和就要最小(从而后面加起来超过的可能更小),将白色总和定义为
。
设
为某棵子树中黑色点的权和,
为白色点权和,子树中选黑色的点集为
,白色为
,那么
然后进行树形背包。
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
int N,X[1001],P,maxn,f[1001][5001],g[1001];
vector<int> point[1001];
void dfs(int u){
for(int v:point[u])dfs(v);
bool c=false;
memset(f[0],0x3f,sizeof(f[0]));
f[0][0]=0;
for(int v:point[u]){
c=!c;
memset(f[c],0x3f,sizeof(f[0]));
for(int j=0;j<=X[u];++j){
if(j>=X[v])f[c][j]=min(f[c][j],f[!c][j-X[v]]+g[v]);
if(j>=g[v])f[c][j]=min(f[c][j],f[!c][j-g[v]]+X[v]);
}
}
for(int i=0;i<=X[u];++i)g[u]=min(g[u],f[c][i]);
}
int main(){
scanf("%d",&N);
for(int i=2;i<=N;++i)scanf("%d",&P),point[P].push_back(i);
for(int i=1;i<=N;++i)scanf("%d",X+i);
memset(g,0x3f,sizeof(g));
dfs(1);if(g[1]<0x3f3f3f3f)puts("POSSIBLE");else puts("IMPOSSIBLE");
}