对于节点 uu 而言,他的儿子就是 vv。我们定义 szusz_u 表示以节点 uu 为根的子树的节点数量。那么可以得到 szu=1+szvsz_u = 1 + \sum sz_v,显然需要一次 DFS\texttt{DFS} 来计算所有的 szisz_i,这次的 DFS\texttt{DFS} 就是预处理。

考虑 dp\texttt{dp},换根 dp\texttt{dp},顾名思义,就是要换根,那么就可以考虑从 fufvf_u \to f_v,但在转移时,节点的深度会发生改变。

  • 所有是 vv 的子树,节点深度都会减少 11,那么总和就减少 szvsz_v
  • 所有不是 vv 的子树,节点深度都会增加 11,那么总和就加上 nszvn-sz_v

综上所述,我们就可以得到状态转移方程为:

fv=fuszv2+n\Large f_v = f_u - sz_v * 2 + n
#include <iostream>
#include <vector>
#define int long long
using namespace std;
const int N = 1e6 + 5; 
vector<int> g[N];
int sz[N], f[N], dep[N], n;
inline void dfs(int u, int fa)
{
	sz[u] = 1;//记录大小 
	dep[u] = dep[fa] + 1;//记录深度 
	for(int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if(v == fa) continue;
		dfs(v, u);//往下深搜 
		sz[u] += sz[v];//加上儿子的大小 
}
inline void dp(int u, int fa)
{
	for(int i = 0; i < g[u].size(); i++){
		int v = g[u][i];
		if(v == fa) continue;
		f[v] = f[u] - sz[v] * 2 + n;//dp 
		dp(v, u);//继续往下dp 
	}
}
signed main()
{
	cin >> n;
	for(int i = 1; i < n; i++){
		int u, v;
		cin >> u >> v;
		g[u].push_back(v);
		g[v].push_back(u);
	}
	dfs(1, 1);
	for(int i = 1; i <= n; i++) f[1] += dep[i];
	dp(1, 1);
	int ans = -1;
	int id;
	for(int i = 1; i <= n; i++){//统计答案 
		if(f[i] > ans){//如果大于ans,就记录 
			ans = f[i];
			id = i;//编号 
		}
	}
	cout << id;//输出 
	return 0;//华丽结束 
}