加载中...

7.10——875F

875F

由于最近在学树上背包,因此今天挑了一道树上背包的题来做。没想到这么难qwq。。。

任意一条路径的权值只有三种情况:

  • 全0 \(\Rightarrow\) 1
  • 全1 \(\Rightarrow\) 0
  • 既有0又有1 \(\Rightarrow\) 2

最优答案显然是所有路径 \(MEX\) 均为 \(2\) -> 答案上界为 \(n(n+1)\)

考虑将计算最大价值转化为计算最小折损:记录初始答案为 \(n(n+1)\)。折损只会在同色连通块内发生,且计算折损的方式为:

  • 大小为 \(x\) 的全 \(0\) 连通块,折损为 \(x*(x+1)/2\)
  • 大小为 \(x\) 的全 \(1\) 连通块,折损为 \(x*(x+1)\)

一个看似很好的贪心想法——交替涂01。这样可以让所有长度 \(>1\) 的路径权值均为 \(2\),而只有长度为 \(1\)(即孤点)存在折损。此时贡献为:\(n(n+1) - cnt_{0} - 2cnt_{1}\)

由于 \(cnt_{0} + cnt_{1} = n\),因此若将交替涂色的折损看做 \(cnt_{0} + 2cnt_{1}\),则最大折损 \(<=2n\)

只有当路径上颜色均一样时才会存在折损,考虑树中最大连通块的大小:设为 \(k\),则该连通块造成的折损至少为:\(k*(k+1)/2\)(全0为 \(k*(k+1)/2\),全1为 \(k*(k+1)\))。由于已经存在了一种最小折损为 \(O(n)\) 数量级的方案,因此可以说明 \(k\)\(O(\sqrt n)\) 级别的,即树中同色的最大连通块大小大约为 \(O(\sqrt n)\)

考虑 \(O(n\sqrt n)\) 的算法:

\(f[u][0/1][j]\):考虑子树 \(u\)\(u\) 填0/1,且 \(u\) 所在的同色连通块大小为 \(j\),总折损最小值。

假设当前正在遍历 \(u\) 的某个儿子 \(v\),考虑将已遍历的子树 \(u\) 和正在遍历的子树 \(v\) 合并:

  1. \(u\)\(v\) 数字不同:显然合并两个连通块,连通块1中的任意点 \(a\) 和 连通块2中的任意点 \(b\) 均不会产生新的折损。因此合并后子树的折损为两棵子树内部的折损之和:
  • u = 0, v = 1:

\[f[u][0][i] = f[u][0][i] + f[v][1][j] \]

  • u = 1, v = 0:

\[f[u][1][i] = f[u][1][i] + f[v][1][j] \]

  1. \(u\)\(v\) 数字相同:此时合并两个连通块,\(u\) 所在的同色连通块 和 \(v\) 所在的同色连通块 的任意两点之间会产生新的折损,两棵子树合并后需要将其计入到总折损中:
  • u = 0, v = 0: 新折损为 \(i * j\)

\[f[u][0][i + j] = f[u][0][i] + f[v][0][j] + i * j \]

  • u = 1, v = 1: 新折损为 \(2 * i * j\)

\[f[u][1][i + j] = f[u][1][i] + f[v][1][j] + 2 * i * j \]

上述四种转移同时进行即可,注意需要使用辅助数组 \(g[0/1][i]\) 进行辅助转移。

此题卡空间,可能需要空间压缩上的代码重构。但不想浪费时间再调了,样例过了就是过了!(叉腰)

code

posted @ 2025-07-10 20:01  jxs123  阅读(6)  评论(0)    收藏  举报