[BZOJ1131][POI2008]Sta

[BZOJ1131][POI2008]Sta

试题描述

给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

输入

给出一个数字N,代表有N个点.N<=1000000 下面N-1条边.

输出

输出你所找到的点,如果具有多个解,请输出编号最小的那个.

输入示例

8
1 4
5 6
4 5
6 7
6 8
2 4
3 4

输出示例

7

数据规模及约定

见“输入

题解

设 f[i] 表示整棵树以 i 为根时深度总和。不妨先令 1 为根节点,则 f[i] 分为两部分,子树 i 的和整棵树减去子树 i 的答案。对于前半部分显然从下往上 dp 一下就好了,对于后半部分显然从上往下 dp 一下就好了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define maxn 1000010
#define maxm 2000010
#define LL long long

int n, m, head[maxn], nxt[maxm], to[maxm];

void AddEdge(int a, int b) {
	to[++m] = b; nxt[m] = head[a]; head[a] = m;
	swap(a, b);
	to[++m] = b; nxt[m] = head[a]; head[a] = m;
	return ;
}

LL f[maxn];
int siz[maxn];
void dp1(int u, int fa) {
	f[u] = siz[u] = 1;
	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) {
		dp1(to[e], u);
		siz[u] += siz[to[e]];
		f[u] += f[to[e]] + siz[to[e]];
	}
	return ;
}
void dp2(int u, int fa) {
	for(int e = head[u]; e; e = nxt[e]) if(to[e] != fa) {
		f[to[e]] = f[u] + n - (siz[to[e]] << 1);
		dp2(to[e], u);
	}
	return ;
}

int main() {
	n = read();
	for(int i = 1; i < n; i++) {
		int a = read(), b = read();
		AddEdge(a, b);
	}
	
	dp1(1, 0);
	dp2(1, 0);
	
	int mni = 0; f[0] = -1;
	for(int i = 1; i <= n; i++) if(f[mni] < f[i]) mni = i;
	printf("%d
", mni);
	
	return 0;
}
原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6490356.html