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;
}
标签:STA,sizes,ll,next,fa,Station,节点,now,P3478
From: https://www.cnblogs.com/pure4knowledge/p/18084077