Luogu P1122 最大子树和

题目链接

题目大意:给定一棵树,每个点带点权,请你求出点权和最大的联通块和是多少。

树形DP简单题

f[x]为以x为根的子树,含x的联通块点权最大和。对于每个v(v∈son(x)),只要f[v]不是负数就把v选上。

f[x]=∑max(f[son(x)],0)

#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
inline int read() {
    char ch;
    bool bj=0;
    while(!isdigit(ch=getchar()))
        bj|=(ch=='-');
    int res=ch^(3<<4);
    while(isdigit(ch=getchar()))
        res=(res<<1)+(res<<3)+(ch^(3<<4));
    return bj?-res:res;
}
void printnum(int x) {
    if(x>9)printnum(x/10);
    putchar(x%10+'0');
}
inline void print(int x,char ch) {
    if(x<0) {
        putchar('-');
        x=-x;
    }
    printnum(x);
    putchar(ch);
}
int f[16005],a[16005],h[16005];
struct Edge {
    int to,nxt;
} w[16005<<1];
int cnt,n;
inline void AddEdge(int x,int y) {
    w[++cnt].to=y;
    w[cnt].nxt=h[x];
    h[x]=cnt;
}
int ans=-0x3f3f3f3f;
void DFS(int x,int fa) {
    for(int i=h[x]; i; i=w[i].nxt) {
        int v=w[i].to;
        if(v==fa)continue;
        DFS(v,x);
        f[x]+=max(f[v],0);
    }
    f[x]+=a[x];
    ans=max(ans,f[x]);
}
signed main() {
    n=read();
    for(int i=1; i<=n; i++)a[i]=read();
    int x,y;
    for(int i=1; i<n; i++) {
        x=read();
        y=read();
        AddEdge(x,y);
        AddEdge(y,x);
    }
    DFS(1,0);
    print(ans,'\n');
    return 0;
}

 

posted @ 2019-08-19 21:03  Soledad_S  阅读(151)  评论(0编辑  收藏  举报