随笔 - 164  文章 - 0  评论 - 4  阅读 - 9771

换根DP

换根DP

无根树上的DP?


相关资料

第一个例题距离和
洛谷类似题 - 洛谷 P3478 [POI2008] STA-Station

有一棵 n(1n100000) 个点的无根树,请求出每个点到其他所有点的距离的和。定义两个点的距离为它们的简单路径上经过了多少条边。

朴素的思想就是枚举每个点作为根遍历整棵树,那么 O(n2) 即可解决该问题,但是可以注意到,父节点和子节点各自作为根节点时,数值关系可以传递

定义两个数组 f 和 v:
f[i] 表示以节点 i 为根的子树中的点到 i 的距离和
v[i] 表示把节点 i 的父亲 x 作为节点 i 的孩子节点时以 x 为根的子树中的点到 i 的距离和

那么第一次 dfs 时可以维护数组 f 的值,f[i]=sz[i]1+f[j],j 为 i 的子节点,sz[i]为以 i 为根的子树节点数
第二次 dfs 可以维护数组 v 的值,v[t]=v[u]+f[u]f[t]sz[t]+nsz[t];,t 为 u 的子节点

未验证的代码

int n, sz[N], f[N], v[N];
vector<int> e[N];
/*
f[i] 表示以节点 i 为根的子树中的点到 i 的距离和
v[i] 表示把节点 i 的父亲 x 作为节点 i 的孩子节点时以 x 为根的子树中的点到 i 的距离和
*/
void dfs1(int u, int fa){
sz[u] = 1;
f[u] = 0;
for(auto v : e[u]){
if(v == fa) continue;
dfs1(v, u);
sz[u] += sz[v];
f[u] += f[v];
}
f[u] += sz[u] - 1;
return ;
}
void dfs2(int u, int fa){
for(auto t : e[u]){
if(t == fa) continue;
v[t] = v[u] + f[u] - f[t] - sz[t] + n - sz[t];
dfs2(t, u);
}
return ;
}
void solve(){
cin >> n;
for(int i = 1; i < n; ++ i){
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= n; ++ i){
cout << f[i] + v[i] << '\n';
}
return ;
}

第二个例题 流
依旧是考虑以节点 x 为根的子树可以承担的最大流量,以及将节点 x 的父节点作为子节点时可以承担的最大流量,此问题还得考虑边对转移的影响

第三个例题 最长路径
类似于树的直径?


例题

综合运用

模板题

首先需要发现一点的是,对于一个有根树,无论你怎么执行操作,对于一组父子节点 uv,只要你不选择节点 v 进行操作,那么节点 u 和节点 v 的权值就永远不变。所以想要所有节点权值均相等,我们从根开始 dfs 遍历,遇到权值不相等的子节点则选择节点 v 异或 a[u]a[v]即可获得一次答案
不可能对于每个节点都做一次dfs,那么考虑换根DP的做法。可以发现,当根节点从节点 u 传递给子节点 v 的时候,受到影响的答案只有节点 u 和节点 v 之间的关系。原本选择节点 v 进行修改操作,现在改为节点 u 进行修改操作即可,即 ans[v]=ans[u](a[u]a[v])×sz[v]+(a[u]a[v])×(nsz[v])
所以利用换根DP,可以 O(n) 处理该问题

posted on   Qiansui  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
历史上的今天:
2022-10-30 数论基础+裴蜀定理+线性同余方程+乘法逆元+中国剩余定理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

点击右上角即可分享
微信分享提示