换根DP
- \(思路:\)
\(换根DP通常需要两次dfs\)
\(第一次dfs预处理诸如深度、点权和之类的信息\)
\(第二次dfs开始进行换根动态规划\)
- \(换根DP通常不会指定根节点,并且根节点的变化会对一些值产生影响,例如子节点深度和、点权和产生影响。\)
- \(本题中, 以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;
}