这个题比较好做,但由于首次接触,还是写一下博客。
首先,我们简单考虑确定了某个根的情形,那么我们从根出发dfs一遍,求出每个结点的子树和求和就可以了。
然后,我们考虑其它的结点为根的情形,注意到如果我们已经求出了某个结点为根的答案为ans[u],那么与u相邻的v结点的答案ans[v],可以O(1)转移,因为我们把根从u换成v的区别在于我们少了v为根的子树的贡献,多了u为根的子树的贡献,ans[v]=ans[u]-sz[v]+n-sz[v],这样只需要再dfs一次即可求出所有点为根的答案。
简单题,但换根的思想值得学习。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=2e5+7;
vector<int> G[N];
int sz[N];
ll ans[N];
int n;
void dfs1(int u,int fa) {
sz[u]=1;
for(auto &v:G[u]) {
if(v==fa) continue;
dfs1(v,u);
sz[u]+=sz[v];
}
ans[1]+=sz[u];
}
void dfs2(int u,int fa) {
if(u!=1) {
ans[u]=ans[fa]-sz[u]+n-sz[u];
}
for(auto &v:G[u]) {
if(v==fa) continue;
dfs2(v,u);
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<n;i++) {
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
printf("%lld\n",*max_element(ans+1,ans+1+n));
return 0;
}