【树形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
",sum);
}
原文地址:https://www.cnblogs.com/Vocanda/p/12691086.html