CodeForces 1324F. Maximum White Subtree【换根DP】

删除回忆录丶 提交于 2020-03-13 09:32:06

传送门

题意

给一颗树,每个节点有 \(1\)\(-1\) 两种权值,问对于每一个点,包含它的联通块权值最大是多少。

题解

第一次写换根DP,其实并不难。相反 E 题记忆化搜索没想出来是真的煞笔。
就是一个最板的换根DP,先把 \(1\) 视作根节点,算出每个点的最大子树。
然后再进行树形DP,每次向儿子转移时将自己、父亲、其他儿子的最大总权传给儿子。

代码

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <queue>
using namespace std;
typedef long long LL;
const int N=2e5+10;
const int M=1e6+10;
int n,a[N],maxs[N],ans[N];
vector<int> g[N];

void dfs1(int u,int fa){
    maxs[u]=a[u];
    for(int v:g[u]){
        if(v==fa) continue;
        dfs1(v,u);
        if(maxs[v]>0) maxs[u]+=maxs[v];
    }
}

void dfs2(int u,int fa,int w){
    if(w<0) w=0;
    ans[u]=maxs[u]+w;
    for(int v:g[u]){
        if(v==fa) continue;
        if(maxs[v]>0) dfs2(v,u,w+maxs[u]-maxs[v]);
        else dfs2(v,u,w+maxs[u]);
    }
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(a[i]==0) a[i]=-1;
    }
    for(int i=1,u,v;i<n;i++){
        scanf("%d%d",&u,&v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs1(1,0);
    dfs2(1,0,0);
    for(int i=1;i<=n;i++) printf("%d ",ans[i]);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!