CF1092F Tree with Maximum Cost 题解

考虑这是一个 树形dp 一个换根dp 

设$f[i]$ 表示以 i 为根的子树内 那个题目要求的子树代价和

那么考虑 换根的时候 $g[i]$ 数组 以 i 为整颗子树的根 怎么转移

其实 只有自己画图 才能深刻理解这个转移的过程吧

那么 我们不妨 模拟一下这个计算的过程 对于每一个子树的点权和为size sum表示 整个子树的权值和

假设 存在一条x->y的边 那么此时 $g[x]$ 已经求出来了 那么考虑 $g[y]$ 怎么求解 

此时 y 变成了整颗树的根 那么 先考虑 y原来子树的部分 那么答案是 $f[y]$ 那么考虑 此时

对于 x 除了 y 的那部分 的另外一部分 的子树 答案就是 $g[x]-(f[y]+size[y])$ 此时由于x和y 的那一条边的存在 

所以 此时 x 除了 y 的那部分 的另外一部分 的子树 会因为深度都增加1 此时这部分 的答案 增加了 $sum-size[y]$

那么 $$g[y]=f[y]+(g[x]-(f[y]+size[y])+(sum-size[y]))$$

化简之后 我们发现 $$g[y]=g[x]+sum-size[y]-size[y]$$ 

那么  我们发现 此时我们就省略了一个数组 yyy

#include<bits/stdc++.h>
using namespace std;
template<typename T>inline void read(T &x) {
    x=0;T f=1,ch=getchar();
    while(!isdigit(ch))     {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x*=f;
}
typedef long long ll;
const int N=201000;
struct gg {
    int y,next;
}a[N<<1];
ll n,m,tot,x,y,w[N],lin[N],size[N],d[N];
ll f[N],sum;
inline void add(int x,int y) {
    a[++tot].y=y;
    a[tot].next=lin[x];
    lin[x]=tot;
}
inline void dfs(int x,int fa) {
    size[x]=w[x];
    for(int i=lin[x];i;i=a[i].next) {
        int y=a[i].y;
        if(y==fa) continue;
        d[y]=d[x]+1;
        f[1]=f[1]+(ll)(d[y]*w[y]);
        dfs(y,x);
        size[x]+=size[y];
    }
}
inline void dfss(int x,int fa) {
    for(int i=lin[x];i;i=a[i].next) {
        int y=a[i].y;
        if(y==fa) continue;
        f[y]=f[x]+sum-size[y]-size[y];
        dfss(y,x);
    }
}
int main() {
    read(n); 
    for(int i=1;i<=n;i++) read(w[i]),sum+=w[i];
    for(int i=1;i<n;i++) {
        read(x); read(y);
        add(x,y); add(y,x);
    } 
    dfs(1,0);
    dfss(1,0);
    ll ans=0;
    for(int i=1;i<=n;i++) ans=max(ans,f[i]);
    cout<<ans<<endl;
    return 0;
} 
View Code

 

posted @ 2019-10-23 16:57  Tyouchie  阅读(154)  评论(0编辑  收藏  举报