https://www.luogu.com.cn/problem/P3478
一道换根DP题。设f[i]为以i为根的答案。先通过一遍dfs,求出f[1]的值。再自上而下进行DP,求出所有儿子节点的值。若节点u的父亲为fa,我们考虑根从fa变为u后,f[fa]怎样得到f[u]。
再u下方的节点(siz[u])贡献会减去1,在u及其上方(n - siz[u])的贡献会加上1.那么f[u] = f[fa] + n - 2 * siz[u].
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N = 1e6 + 100;
typedef long long LL;
LL f[N], dn[N], siz[N];
int head[N], cnt;
int n;
struct Edge {
int v, nxt;
} e[N <<1];
void dfs1(int u, int fa) {
siz[u] = 1;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if( v == fa) continue;
dfs1(v, u);
dn[u] += dn[v] + siz[v];
siz[u] += siz[v];
}
}
void dfs2(int u, int fa) {
if(u == 1)
f[u] = dn[u];
else f[u] = f[fa] + n - 2 * siz[u];
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].v;
if( v == fa) continue;
dfs2(v, u);
}
}
void AddEdge(int u, int v, int w) {
e[++cnt].v = v;
e[cnt].nxt = head[u];
head[u] = cnt;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i < n; i ++) {
int u, v;
scanf("%d%d", &u, &v);
AddEdge(u, v, 1), AddEdge(v, u, 1);
}
dfs1(1, 0);
dfs2(1, 0);
LL ans = 0;
int id;
for(int i = 1; i <= n; i ++) {
if( f[i] > ans) {
ans = f[i];
id = i;
}
}
printf("%d
", id);
return 0;
}