树形DP

换根DP

STA-Station

  1. \(思路:\)
    \(换根DP通常需要两次dfs\)
    \(第一次dfs预处理诸如深度、点权和之类的信息\)
    \(第二次dfs开始进行换根动态规划\)
  2. \(换根DP通常不会指定根节点,并且根节点的变化会对一些值产生影响,例如子节点深度和、点权和产生影响。\)
  3. \(本题中, 以s_i表示以i为根的子树的结点个数,dep_i表示i节点的深度(这两个变量均是选1为根节点时),f_i表示以i为根的深度和,第一次dfs求出f_1后换根DP去求出其他f_i的值\)
    \(状态转移:f_v=f_u-s_v+n-s_v=f_u+n-2s_v\)
    \(f_v由f_u转移体现换根\)
    \(解释:所有在v的子树上的结点深度都减少了1,共减少了s_v;所有不在v的子树上的结点深度都增加了1,共增加了n-s_v\)
点击查看代码
#include<bits/stdc++.h>

using namespace std;
using i64=long long;

const int N=1000010,M=2*N;
int n;
int h[N],e[M],ne[M],idx;
i64 f[N];
int dep[N],sz[N];

void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}

void dfs(int u,int fa){
    sz[u]=1;
    dep[u]=dep[fa]+1;

    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if(v==fa) continue;
        dfs(v,u);
        sz[u]+=sz[v];
    }

}

void get_ans(int u,int fa){
    for(int i=h[u];~i;i=ne[i]){
        int v=e[i];
        if(v==fa) continue;
        f[v]=f[u]+n-2*sz[v];
        get_ans(v,u);
    }
}

signed main(){
    
    cin>>n;
    memset(h,-1,sizeof h);
    for(int i=1;i<=n-1;i++){
        int x,y;
        cin>>x>>y;
        add(x,y),add(y,x);
    }

    dfs(1,1);

    for(int i=1;i<=n;i++) f[1]+=dep[i];

    get_ans(1,1);

    i64 ans=-1;
    int id;
    for(int i=1;i<=n;i++){
        if(f[i]>ans){
            ans=f[i];
            id=i;
        }
    }
    cout<<id<<endl;
    return 0;

}
posted @ 2025-11-10 20:47  gudelaike  阅读(2)  评论(0)    收藏  举报