题意: 给定一个点的树,求以其中哪个点为根时可使得所有点的深度最小。
题解: 表示以为根的所有结点深度和。那么即答案。
具体实现:初始可以随便指定一个点为根,然后求出以为根的所有点的深度,,然后遍历其所有的子结点,求出以子结点为根的深度和来更新最小深度,一次即可。求以子结点为根的深度和即将子结点拉成根,那么其子树的深度必定都减,非子树部分的深度必定都加
注意避坑:不能直接将一个结点拉成根结点,必须在其父结点为根的树的基础上,将拉为根时,才符合的子树深度都减是非的子树深度都加


代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef long long ll;
const int N = 1e6 + 10, M = N << 1;
int n, f[N];
int h[N], e[M], ne[M], idx;
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;  
}

int dep[N], siz[N];
void dfs1(int u, int fa) {
    siz[u] = 1;
    for(int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if(v == fa) continue;
        dep[v] = dep[u] + 1;
        dfs1(v, u);
        siz[u] += siz[v];
    }
}

void dfs2(int u, int fa) {
    for(int i = h[u]; i != -1; i = ne[i]) {
        int v = e[i];
        if(v == fa) continue;
        f[v] = f[u] - siz[v] + (n - siz[v]);
        dfs2(v, u);
    }
}

int main()
{
    memset(h, -1, sizeof h);
    scanf("%d", &n);
    for(int i = 1; i < n; i++) {
        int a, b; scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }

    dfs1(1, 0);
    for(int i = 1; i <= n; i++) f[1] += dep[i];
    dfs2(1, 0);
    int res = f[1];
    for(int i = 2; i <= n; i++) res = min(res, f[i]);
    printf("%d\n", res);
    return 0;
}