题解【洛谷P3478】[POI2008]STA-Station

题面

(dp_i)表示以(i)为根节点时所有节点的深度之和。

首先以 (1) 为根求出所有点深度之和(dp_1),并预处理每个点的子树大小。

(v)(u) 的孩子,考虑根从 (u) 移动到 (v)(dp_v) 产生的影响。

不难发现,(v) 子树内所有点深度 (−1),其余点深度 (+1)

(dp_v = dp_u − size_v + (n − size_v))

( ext{DFS}) 一次即可求出所有的 (dp_i)

注意开( ext{long long})

代码如下:

#include <bits/stdc++.h>
#define itn int
#define gI gi
#define int long long

using namespace std;

inline int gi()
{
	int f = 1, x = 0; char c = getchar();
	while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return f * x;
}

const int maxn = 1000003;

int n, m, head[maxn], ver[maxn * 2], nxt[maxn * 2], tot;
int sz[maxn], dp[maxn], dep[maxn], ans, cnt, sum;

inline void add(int u, int v) {ver[++tot] = v, nxt[tot] = head[u], head[u] = tot;}

void dfs1(int u, int f)
{
	dep[u] = dep[f] + 1, sz[u] = 1;
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = ver[i];
		if (v == f) continue;
		dfs1(v, u);
		sz[u] += sz[v];
	}
}

void dfs2(int u, int f)
{
	for (int i = head[u]; i; i = nxt[i])
	{
		int v = ver[i];
		if (v == f) continue;
		dp[v] = dp[u] + n - 2 * sz[v];
		dfs2(v, u);
	}
}

signed main()
{
	//freopen(".in", "r", stdin);
	//freopen(".out", "w", stdout);
	n = gi();
	for (int i = 1; i < n; i+=1) 
	{
		int u = gi(), v = gi();
		add(u, v), add(v, u);
	}
	dfs1(1, 0);
	for (int i = 1; i <= n; i+=1) dp[1] += dep[i];
	dfs2(1, 0);
	for (int i = 1; i <= n; i+=1)
	{
		if (ans < dp[i]) ans = dp[i], cnt = i;
	}
	printf("%lld
", cnt);
	return 0;
}
原文地址:https://www.cnblogs.com/xsl19/p/12253784.html