CF1534H 题解

第一次 DP 的部分和后面交互的部分现有的两篇题解都讲的比较清楚了,这里注意补充解释一下换根和计算答案的部分,(让像我这样的菜鸡容易理解一点)。

我们先列出第一次 DP 的式子: \[ f_u=\max\limits_{i=0}^{size-1} f_v+i \] 那么我们考虑当前节点是 \(u\) ,新的根是 \(v\),那么此时我们要抛弃掉 \(v\)\(u\) 的贡献并且加入 \(fa_u\)\(u\) 的贡献。考虑直接将与 \(u\) 相连的所有点按 \(f\) 值进行排序,那么每次的 \(v\) 将整个数组分割成一个前缀和一个后缀,式子其实就是上面那个式子,但是后缀部分的 \(i\) 要减去当前这个 \(v\) 所多算的 \(1\)。因此不需要什么平衡树,只用预处理前缀最大值、后缀最大值,中间再合并一下就好了。

计算答案的部分则是简单的分类讨论。我们在计算前仍然需要对所有儿子按 \(f\) 值排序。对于当前根是 \(u\) ,有 \(3\) 种情况:

  1. 询问的两个点分别在当前节点的两个不同子树内,则贡献为 \(\max f_{v0}+f_{vi}+i-1\)
  2. 询问的两个点中有一个是当前根,则贡献为 \(f_{v0}+deg_u-1\)
  3. 询问的两个点都是当前的根,则贡献为 \(deg_u\)

放一下这个关键的 DFS 部分的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bool cmp(int x,int y){
return f[x]>f[y];
}
void dfs2(int u,int fa){
sort(e[u].begin(),e[u].end(),cmp);
for(int i=1;i<e[u].size();i++)maxm=max(maxm,f[e[u][0]]+f[e[u][i]]+i-1);
maxm=max(maxm,max(f[e[u][0]]+(int)e[u].size()-1,(int)e[u].size()));
pre[0]=suf[e[u].size()+1]=0;
for(int i=0;i<e[u].size();i++)pre[i+1]=max(pre[i],f[e[u][i]]+i);
for(int i=e[u].size()-1;i>=0;i--)suf[i+1]=max(suf[i+2],f[e[u][i]]+i);
for(int i=0;i<e[u].size();i++){
res[e[u][i]]=max(pre[i],suf[i+2]-1);
}
for(int i=0;i<e[u].size();i++){
if(e[u][i]==fa)continue;
f[u]=max((int)e[u].size()-1,res[e[u][i]]);
dfs2(e[u][i],u);
}
}