【树形dp】 bzoj1131 Sta
题目
给出一个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
Sample Output
7
分析
这个题还是比较简单的,如果数据小的话,那么挨个枚举应该是没什么大问题,但是这个题数据就很大,所以单纯的一个个顶点来枚举显然是不可能实现的。所以我们应该找一下每个点之间的关系,但是总体来说就是一个深搜的思想。
我们来想象一下,一棵树,一开始给你一个根,这个根只有一颗子树,然后我们向下依次推,每次更改根节点,那么上一个根节点及其子树的深度都是要-1的,而现在这个节点的子树深度是+1的,所以根据这个,我们可以进行一下简化。
然后我们就可以把每个点的“上"边的深度加上”下“边的深度进行比较,然后得出最后的结果。
代码
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn = 1e6+10; #define ll long long int n,head[maxn],cnt=1; struct Node{ int from,to,next; }e[maxn<<1]; ll si[maxn],d[maxn],u[maxn],fa[maxn]; void Add(int from,int to){ e[cnt].from=from; e[cnt].to=to; e[cnt].next=head[from]; head[from]=cnt++; } void Dfs1(int now,int fu){//普通的深搜,找出深度。 fa[now]=fu; si[now]=1; for(int i=head[now];i;i=e[i].next){ int to=e[i].to; if(to == fu)continue; Dfs1(to,now); si[now]+=si[to]; d[now]+=d[to]+si[to]; } } void Dfs2(int now){//找到以这个点为根时“父树”的全部深度 if(now!=1) u[now]=u[fa[now]]+d[fa[now]]-d[now]-2*si[now]+n; for(int i=head[now];i;i=e[i].next){ int to=e[i].to; if(to==fa[now])continue; Dfs2(to); } } int main(){ scanf("%d",&n); for(int i=1;i<n;++i){ int x,y; scanf("%d%d",&x,&y); Add(x,y); Add(y,x); } Dfs1(1,0); Dfs2(1); ll ans = 0; int sum; for(int i=1;i<=n;++i){ if(u[i]+d[i]>ans){//一个个的评判,最终得出结果 ans=u[i]+d[i]; sum = i; } } printf("%d\n",sum); }
$Never\ Give\ Up$