[BZOJ1131]Sta
给出一个N个点的树,找出一个点来,以这个点为根的树时,所有点的深度之和最大
傻逼题
先预处理一下根为1的时候,所有的dep,siz
和子树深度和sum
记(dp[1]=sum[1])
现在我们有了1作为根时的答案,考虑把2换成根会发生什么
对于2的子树,所有点的dep
值-1
对于其余的所有点,dep值加1
所以
[dp[2]=dp[1]-size[2]+(n-size[2])
]
推广一下:
[dp[v]=dp[u]-siz[v]+(n-siz[v])=dp[u]+n-2*siz[v]
]
没了?没了。
得到的经验和结论:树形'dp'时,不一定是自底向上的,有时候父亲的答案我们已经知道,孩子的答案可能从父亲的答案转移过来。
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=x;i<=y;i++)
using namespace std;
const int maxn=1000010;
struct Edge{int v,nex;}edge[maxn<<1];
typedef long long ll;
int n,cnt=0;
int head[maxn],siz[maxn],dep[maxn];
ll sum[maxn],dp[maxn];
void addEdge(int u,int v){
edge[++cnt]=(Edge){v,head[u]};head[u]=cnt;
}
void dfs1(int u,int fa){
siz[u]=1;sum[u]=dep[u]=dep[fa]+1;
for(int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if (v==fa) continue;
dfs1(v,u);
siz[u]+=siz[v];sum[u]+=sum[v];
}
}
void dfs2(int u,int fa){
for (int i=head[u];i;i=edge[i].nex){
int v=edge[i].v;
if (v==fa) continue;
dp[v]=dp[u]+n-2*siz[v];
dfs2(v,u);
}
}
int read(){
int x=0;char ch=getchar();
while (!isdigit(ch)) ch=getchar();
while (isdigit(ch)) x=x*10+ch-48,ch=getchar();
return x;
}
int main(){
n=read();
rep(i,1,n-1){
int u=read(),v=read();
addEdge(u,v);addEdge(v,u);
}
dfs1(1,0);
dp[1]=sum[1];
dfs2(1,0);
int ans=0;
rep(i,1,n){
if (dp[i]>dp[ans]) ans=i;
}
printf("%d
",ans);
//getchar();
return 0;
}