Codeforces 1187E

乍一看题意比较麻烦,好像要删点求联通性,但其实是相当于求以某一个节点为根时,他的所有后代(儿子,儿子的儿子等等)的儿子的总和最大。

两边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;
}
原文地址:https://www.cnblogs.com/WAautomaton/p/11164903.html