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\) 合并:
- \(u\) 与 \(v\) 数字不同:显然合并两个连通块,连通块1中的任意点 \(a\) 和 连通块2中的任意点 \(b\) 均不会产生新的折损。因此合并后子树的折损为两棵子树内部的折损之和:
- u = 0, v = 1:
- u = 1, v = 0:
- \(u\) 与 \(v\) 数字相同:此时合并两个连通块,\(u\) 所在的同色连通块 和 \(v\) 所在的同色连通块 的任意两点之间会产生新的折损,两棵子树合并后需要将其计入到总折损中:
- u = 0, v = 0: 新折损为 \(i * j\)
- u = 1, v = 1: 新折损为 \(2 * i * j\)
上述四种转移同时进行即可,注意需要使用辅助数组 \(g[0/1][i]\) 进行辅助转移。
此题卡空间,可能需要空间压缩上的代码重构。但不想浪费时间再调了,样例过了就是过了!(叉腰)