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; }