【换根DP】CF1882 D

Bertha 。 2024-02-21 03:15 203阅读 0赞

Problem - D - Codeforces

deb798f4239b42af8fc9c94f32fdb2aa.png

思路:

一个很套路的换根

首先观察到,先对儿子一定比先对父亲操作来的代价小,因此考虑先对儿子操作,再对父亲操作

然后就可以直接换根了,首先考虑树形DP,设dp[u] 为 把 u 子树染成同一种颜色的最小代价

那么根据刚刚的先操作儿子,转移方程为

dp[u] += dp[v] + (a[u] ^ a[v]) * sz[v]

然后换根就正常换就好了

Code:

  1. #include <bits/stdc++.h>
  2. #define int long long
  3. constexpr int N = 2e5 + 10;
  4. constexpr int mod = 998244353;
  5. std::vector<int> adj[N];
  6. int n;
  7. int a[N];
  8. int dp[N], sz[N];
  9. void dfs1(int u, int fa) {
  10. sz[u] = 1;
  11. for (auto v : adj[u]) {
  12. if (v == fa) continue;
  13. dfs1(v, u);
  14. sz[u] += sz[v];
  15. dp[u] += dp[v] + (a[u] ^ a[v]) * sz[v];
  16. }
  17. }
  18. void dfs2(int u, int fa) {
  19. for (auto v : adj[u]) {
  20. if (v == fa) continue;
  21. dp[u] -= (a[u] ^ a[v]) * sz[v] + dp[v];
  22. sz[u] -= sz[v];
  23. int t1 = (a[u] ^ a[v]) * sz[v] + dp[v];
  24. int t2 = sz[v];
  25. dp[v] += (a[v] ^ a[u]) * sz[u] + dp[u];
  26. sz[v] += sz[u];
  27. dfs2(v, u);
  28. dp[u] += t1;
  29. sz[u] += t2;
  30. }
  31. }
  32. void solve() {
  33. std::cin >> n;
  34. for (int i = 1; i <= n; i ++) {
  35. adj[i].clear();
  36. dp[i] = sz[i] = 0;
  37. }
  38. for (int i = 1; i <= n; i ++) {
  39. std::cin >> a[i];
  40. }
  41. for (int i = 1; i <= n - 1; i ++) {
  42. int u, v;
  43. std::cin >> u >> v;
  44. adj[u].push_back(v);
  45. adj[v].push_back(u);
  46. }
  47. dfs1(1, 0);
  48. dfs2(1, 0);
  49. for (int i = 1; i <= n; i ++) {
  50. std::cout << dp[i] << " \n" [i == n];
  51. }
  52. }
  53. signed main() {
  54. std::ios::sync_with_stdio(false);
  55. std::cin.tie(nullptr);
  56. int t = 1;
  57. std::cin >> t;
  58. while (t--) {
  59. solve();
  60. }
  61. return 0;
  62. }

发表评论

表情:
评论列表 (有 0 条评论,203人围观)

还没有评论,来说两句吧...

相关阅读