【AT3536】Bichrome Tree

链接:AT3536
(翻译在讨论中有)

题解

对于一个点 u ,若其为黑色,则以 u 为根的字数中黑色总和为 X u ,白色总和就要最小(从而后面加起来超过的可能更小),将白色总和定义为 f u
B 为某棵子树中黑色点的权和, W 为白色点权和,子树中选黑色的点集为 V B ,白色为 V W ,那么

B = v V B X v + v V W f v
W = v V W X v + v V B f v

然后进行树形背包。

代码

#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");
}

猜你喜欢

转载自blog.csdn.net/ezoixx174/article/details/81607225
今日推荐