P3478 [POI2008] STA-Station

原题链接

WARNING!!! 使用map代替数组不再可靠,因为map的插入查找修改复杂度均为 \(O(logn)\) ,即使unorder_map也不行!!!

题解

我们发现,当一个节点的深度之和已知时(这里认为是根节点),其相邻节点的深度之和也可通过某种方程转移而得,有人称这种方法为换根DP

具体的,将树拆开成图(求深度之和的时候是树),已知节点 \(A\) 向右边相邻一条节点 \(B\) 移动,等价于 \(A\) 左边的节点(包括 \(A\) )到 \(A\) 之后再往右走一步,左边少走一步
怎么表示这个左边右边的节点呢?

再回到树的视角,等价于 \(f[B]=f[A]-size[B]+n-size[B]\) 其中 \(size[B]\) 代表 \(B\) 的子树大小

因为树中父节点与子节点的大头针插入式的边才有这样的感觉??

code

#define ll long long
#include<bits/stdc++.h>
using namespace std;
vector<ll> G[1000005];
ll sizes[1000005],depth[1000005],dp[1000005];
ll n;

void dfs1(ll now,ll fa)
{
    sizes[now]=1;
    depth[now]=depth[fa]+1;
    for(auto next:G[now])
    {
        if(next==fa) continue;
        dfs1(next,now);
        sizes[now]+=sizes[next];
    }
}

void dfs2(ll now,ll fa)
{
    for(auto next:G[now])
    {
        if(next==fa)continue;
        dp[next]=dp[now]-sizes[next]+(n-sizes[next]);
        dfs2(next,now);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(ll i=1;i<n;i++)
    {
        ll x,y;
        cin>>x>>y;
        G[x].emplace_back(y);
        G[y].emplace_back(x);
    }

    dfs1(1,0);
    for(ll i=1;i<=n;i++) dp[1]+=depth[i];
    dfs2(1,0);

    ll ans=0,id;
    for(ll i=1;i<=n;i++)
    {
        if(dp[i]>ans)
        {
            ans=dp[i];
            id=i;
        }
    }

    cout<<id;
    return 0;
}
posted @ 2024-03-19 22:00  纯粹的  阅读(15)  评论(0)    收藏  举报