题解【洛谷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)\)

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

注意开\(\text{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\n", cnt);
	return 0;
}
posted @ 2020-02-02 21:21  csxsi  阅读(125)  评论(0编辑  收藏  举报