P3478 [POI2008]STA-Station
考察:树形dp
想了半天没想出来怎么从父节点的深度和推到子节点深度和,我果然fw
思路:
换根dp模板题.也称二次扫描法,第一次多用于预处理,第二次多用于计算答案.
第一次dfs时,用子节点更新父节点,计算每个结点的子树结点个数,并计算当前假定根的深度和
第二次dfs时,用父节点更新子节点.如图: 可以发现除了2的子树上点外,其余点的深度+1,2子树上的点深度全部-1. 由此推出方程f[v] = f[u]+n-sum[v]-sum[v]
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 typedef long long LL; 5 const int N = 1000010; 6 int n,h[N],idx,sum[N]; 7 LL f[N],ans; 8 struct Road{ 9 int fr,to,ne; 10 }road[N<<1]; 11 void add(int a,int b) 12 { 13 road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 14 } 15 void dfs(int u,int fa) 16 { 17 sum[u] = 1; 18 for(int i=h[u];i!=-1;i=road[i].ne) 19 { 20 int v = road[i].to; 21 if(v==fa) continue; 22 dfs(v,u); 23 f[u] = f[v]+sum[v]; 24 sum[u]+=sum[v]; 25 } 26 } 27 void dfs_up(int u,int fa) 28 { 29 for(int i=h[u];i!=-1;i=road[i].ne) 30 { 31 int v = road[i].to; 32 if(v==fa) continue; 33 f[v] = n-sum[v]+f[u]-sum[v]; 34 dfs_up(v,u); 35 } 36 } 37 int main() 38 { 39 memset(h,-1,sizeof h); 40 scanf("%d",&n); 41 for(int i=1;i<n;i++) 42 { 43 int a,b; scanf("%d%d",&a,&b); 44 add(a,b); add(b,a); 45 } 46 dfs(1,-1); 47 dfs_up(1,-1); 48 for(int i=1;i<=n;i++) ans = max(f[i],ans); 49 for(int i=1;i<=n;i++) 50 if(ans==f[i]) 51 { 52 printf("%d\n",i); 53 break; 54 } 55 return 0; 56 }