[BZOJ1131]Sta

[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\n",ans);
    //getchar();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/ugly-CYW-lyr-ddd/p/11802329.html