题目描述
给出一个$N$个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大
输入输出格式
输入格式
第一行一个数$n$,表示树上共有$n$个点
接下来$n-1$行,表示$n-1$条边;每行两个数,表示这条边的两个端点
输出格式
一个数,表示以该节点为根时,所有点的深度之和最大
思路
- 设$u$为$v$的父节点
- 用$f[u]$表示以u为根节点时的最大深度和,用$size[u]$表示u的子树大小
- 以$u$为根的树,变成以儿子$v$为根的树,
- 那么所有在$v$的子树上的节点的深度都会减1,深度和就会减少$size[v]$,
- 所有不在$v$的子树上的节点的深度都会+1,深度和就会加上$n-size[v]$;
得到公式
$$f[v]=f[u]+n-2*size[v]$$
- 所以,只需求出以1为根节点时的深度和;剩下的答案都可以递推出来
代码
#include<cmath> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #define re register int using namespace std; int const maxn=1e6+50; inline int read(){ int x=0,w=1; char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if(ch=='-') w=-1,ch=getchar(); while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar(); return x*w; } long long sum[maxn],size[maxn],ans[maxn]; int tot=1,dep[maxn],n,h[maxn]; struct data { int v,next; }e[maxn<<1]; inline void add(int u,int v) { e[tot].v=v; e[tot].next=h[u]; h[u]=tot++; } void dfs(int u,int f){ sum[u]=dep[u]=dep[f]+1;size[u]=1; for(re i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==f) continue; dfs(v,u); size[u]+=size[v]; sum[u]+=sum[v]; } } void DFS(int u,int f) { for(re i=h[u];i;i=e[i].next) { int v=e[i].v; if(v==f) continue; ans[v]=ans[u]+n-2*size[v]; DFS(v,u); } } int main() { n=read(); for(re i=1,a,b;i<n;++i) { a=read(),b=read(); add(a,b);add(b,a); } dfs(1,0); ans[1]=sum[1]; DFS(1,0); int pos=0; for(re i=1;i<=n;++i) { if(ans[pos]<ans[i]) pos=i; } printf("%d ",pos); return 0; } /* 8 1 4 5 6 4 5 6 7 6 8 2 4 3 4 */