乍一看题意比较麻烦,好像要删点求联通性,但其实是相当于求以某一个节点为根时,他的所有后代(儿子,儿子的儿子等等)的儿子的总和最大。
两边dfs即可,第一遍dfs随便找一个点为根,求出每个节点的儿子数siz[],第二遍dfs以每个点作为根更新ans。
这里注意:如果u为根,u是v的父亲,且此时u后代的和为siz[u] = val,那么v为根时后代和为val-siz[v]+n-siz[v],以此关系作为第二遍dfs的依据、
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; const int inf = 0x3f3f3f3f; typedef long long ll; int n, tot, head[maxn], siz[maxn]; struct edge{ int to, next; } ed[maxn<<1]; ll ans; inline void init(){ memset( head, -1, sizeof(head) ); tot = 1; ans = 0; for( int i=1; i<=n; i++ ) siz[i] = 1; } inline void add( int u, int v ){ ed[++tot].to = v; ed[tot].next = head[u]; head[u] = tot; ed[++tot].to = u; ed[tot].next = head[v]; head[v] = tot; } inline void FindSiz( int x, int fa ){ for( int i=head[x]; i!=-1; i=ed[i].next ){ int y =ed[i].to; if( y!=fa){ FindSiz(y, x); siz[x] += siz[y]; } } ans += siz[x]; } inline void dfs( int x, int fa, ll val ){ for( int i=head[x]; i!=-1; i=ed[i].next ){ int y = ed[i].to; if( y==fa ) continue; ll tmp = val-siz[y]+n-siz[y]; ans = max( ans ,tmp ); dfs( y, x, tmp ); } } int main(){ scanf("%d", &n); init(); for( int i=1; i<n; i++ ){ int u, v; scanf("%d%d", &u, &v); add( u, v ); } FindSiz(1, 0); dfs( 1, 0, ans ); printf("%lld ", ans); return 0; }