标签:子树 题解 sum 那么 Tree ch 此时 size Cost
考虑这是一个 树形dp 一个换根dp
设$f[i]$ 表示以 i 为根的子树内 那个题目要求的子树代价和
那么考虑 换根的时候 $g[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
标签:子树,题解,sum,那么,Tree,ch,此时,size,Cost 来源: https://www.cnblogs.com/Tyouchie/p/11727278.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。