BZOJ 1131: [POI2008]Sta
1131: [POI2008]Sta
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1370 Solved: 486
[Submit][Status][Discuss]
Description
给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大
Input
给出一个数字N,代表有N个点.N<=1000000 下面N-1条边.
Output
输出你所找到的点,如果具有多个解,请输出编号最小的那个.
Sample Input
8
1 4
5 6
4 5
6 7
6 8
2 4
3 4
1 4
5 6
4 5
6 7
6 8
2 4
3 4
Sample Output
7
HINT
Source
分析
一开始不妨拿1当作根节点,预处理出每个子树的结点个数,然后从1开始DFS,在相邻点种枚举新的根,可以O(1)的得到新的SON数组以及深度之和。
代码
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <iostream> 6 #include <algorithm> 7 8 using namespace std; 9 10 const int N = 5000005; 11 12 int n, id = 1; 13 14 long long sum, ans, son[N]; 15 16 int hd[N], nt[N], to[N], tot; 17 18 void add(int x, int y) 19 { 20 nt[tot] = hd[x]; to[tot] = y; hd[x] = tot++; 21 nt[tot] = hd[y]; to[tot] = x; hd[y] = tot++; 22 } 23 24 void prework(int u, int f, int d) 25 { 26 sum += d; son[u] = 1; 27 28 for (int i = hd[u]; ~i; i = nt[i]) 29 if (to[i] != f)prework(to[i], u, d + 1), son[u] += son[to[i]]; 30 } 31 32 void search(int u, int f, long long s) 33 { 34 if (ans < s || (ans == s && id > u)) 35 ans = s, id = u; 36 37 for (int i = hd[u]; ~i; i = nt[i]) 38 if (to[i] != f)search(to[i], u, s + n - son[to[i]]*2); 39 } 40 41 signed main(void) 42 { 43 scanf("%d", &n); 44 45 memset(hd, -1, sizeof(hd)); tot =0; 46 47 for (int i = 1, x, y; i < n; ++i) 48 scanf("%d%d", &x, &y), add(x, y); 49 50 prework(1, -1, 0); search(1, -1, sum); 51 52 printf("%d\n", id); 53 }
@Author: YouSiki