[POI2008]STA-Station

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;
}

原文地址:https://www.cnblogs.com/wyy0804/p/13731778.html