[题解] CF1882D - Tree XOR
CF1882D - Tree XOR
知识点:换根 DP 。
主要难点是要思考如何操作使得代价最小,这个过程是一个贪心的过程。想到怎么操作,计算答案的过程就是一个板子换根了。
题意
给定一颗
- 记当前根节点为
,一次操作中,可以选择一个点 和任意整数 ,将 子树内所有节点的权值异或 ,代价为一次异或的节点数量。
问当根节点为
思路
假设我们现在选择一个点
因此,如果如此递归考虑,那么我们每次执行操作,必然是从叶子节点到根节点,每次操作都是让当前节点
设
但是,我们现在考虑的代价只是以一个根节点进行考虑的,并不是
设
对于
最后计算结果,
实现
auto Main() -> void { int n; std::cin >> n; std::vector<i64> vw(n); for (auto &x : vw) { std::cin >> x; } std::vector adj(n, std::vector<int>{}); for (int i = 0; i < n - 1; i ++) { int u, v; std::cin >> u >> v; u --; v --; adj[u].emplace_back(v); adj[v].emplace_back(u); } std::vector<int> siz(n); std::vector<i64> dp1(n), dp2(n); auto dfs1 = [&](auto &self, int from, int come) -> void { siz[from] = 1; for (auto to : adj[from]) { if (to == come) { continue; } self(self, to, from); siz[from] += siz[to]; dp1[from] += dp1[to] + (i64(vw[from] ^ vw[to]) * siz[to]); } }; dfs1(dfs1, 0, -1); auto dfs2 = [&](auto &self, int from, int come) -> void { if (come != -1) { dp2[from] = dp1[come] - dp1[from] - (i64(vw[come] ^ vw[from]) * siz[from]) + dp2[come] + (i64(vw[from] ^ vw[come]) * (n - siz[from])); } for (auto to : adj[from]) { if (to != come) { self(self, to, from); } } }; dfs2(dfs2, 0, -1); for (int i = 0; i < n; i ++) { std::cout << dp1[i] + dp2[i] << " \n"[i + 1 == n]; } }
本文作者:FlandreScarlet
本文链接:https://www.cnblogs.com/FlandreScarlet/p/17734262.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步