P3478 [POI2008]STA-Station-动态规划,树形dp

版权声明:原创,勿转 https://blog.csdn.net/qq_42386465/article/details/82957521

给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大

n ≤ 1000000

https://www.luogu.org/problemnew/show/P3478

对于这种挑一个最优点的问题,我们往往先找一个点,计算出其相应的值,在考虑转移到其相邻的点上去。

 状态:f[i]表示以i为根时的答案。

初始化:f[1]等于以1为根所有点深度之和。

转移:u是v的父亲,f[u]的值已经求出,把根从u转到v。就相当于v的子树中的点深度都减小了1,其他点深度增加了1。size数组表示子树的大小(点的个数)。变化量为(n-size[v])+(-size[v])。f[v]=f[u]+n-2*size[v]。

结果:在所有f[1~n]中取最大值。

#include<iostream>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
inline int r()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
const int maxn=1000001;
struct node
{
    int next,to;
}e[maxn<<1];
int cnt,id,n;
int head[maxn];
ll f[maxn],dep[maxn],size[maxn],ans;
inline void add(int x,int y)
{
    e[++cnt].next=head[x];
    e[cnt].to=y;
    head[x]=cnt;
}
inline void dfs(int u,int fa)
{
    size[u]=1;
    dep[u]=dep[fa]+1;
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to!=fa){
            dfs(e[i].to,u);
            size[u]+=size[e[i].to];
        }
    }
}
inline void DFS(int u,int fa)
{
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to!=fa){
            f[e[i].to]=f[u]+n-size[e[i].to]-size[e[i].to];
            DFS(e[i].to,u);
        }
    }
}
int main()
{
    n=r();
    for(int i=1;i<=n-1;i++){
        int x=r(),y=r();
        add(x,y);add(y,x);
    }
    dfs(1,1);
    for(int i=1;i<=n;i++){
        f[1]+=dep[i];
    }
    DFS(1,1);
    for(int i=1;i<=n;i++){
        if(f[i]>ans){
            ans=f[i];
            id=i;
        }
    }
    printf("%d",id);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42386465/article/details/82957521