换根 DP
树形 DP 中的换根 DP 问题又被称为二次扫描,通常不会指定根结点,并且根结点的变化会对一些值,例如子结点深度和、点权和等产生影响。
通常需要两次 DFS,第一次 DFS 预处理诸如深度,点权和之类的信息,在第二次 DFS 开始运行换根动态规划。(摘自OI Wiki)
题意:给定一个n个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和最大。
暴力做法:直接枚举每一个结点为根的情况,DFS求出最优解(时间复杂度为O(n2))
但题目中n的数据范围到达了106,O(n2)的算法是肯定过不了的,所以考虑优化
首先,枚举结点1~n的复杂度是肯定无法省略的 (不然还求个毛的最优解啊。。。)
那么考虑如何优化才能在更短的时间内求出每个结点的价值
可以思考一个问题:以结点i为根的树的深度之和与什么东西会产生联系?盲猜一波肯定不是父结点就是子结点啊 啊不貌似这两个是等价的哎
所以顺着树型DP的思路,用f[x]表示以结点x为根时树的深度之和,尝试去寻找f[u]与f[v]之间的关系(v为u的子结点)
我们发现:可以把以v为根的这整棵树分为两部分,一部分(为了方便,我们把它称作p部分)是当u为v的父亲时以v为根的子树上的结点,另一部分(q部分)就是余下的所有结点(有点抽象?画个图理解下:)
当根结点从u变为v时,p部分的结点深度都减少了1,q部分都增加了1
所以我们可以考虑先用一遍DFS求出令结点x(随意取一个结点)为根时的最大深度,同时预处理出x为根时以每个结点i为根的子树的结点数量sum[i]
由上面的推导可以知道:f[v]=f[u]-sum[v] (p部分减少的总深度)+n-sum[v] (q部分增加的总深度,q部分的结点总数实际上就等于总的结点数减去p部分的结点数),
即f[v]=f[u]+n-2*sum[v],再用一遍DFS即可求解
max(f[i]),i from 1 to n即为目标解
代码时间到~~~
#include<bits/stdc++.h>
using namespace std;
int num=1,head[1000005],n,ansx,now,sum