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