[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\n", mni);
return 0;
}