题目:

牛妹有一张连通图,由n个点和n-1条边构成,也就是说这是一棵树,牛妹可以任意选择一个点为根,根的深度为0,对于任意一个非根的点,我们将他到根节点路径上的第一个点称作他的父节点,例如1为根,1-4的;路径为1-3-5-4时,4的父节点是5,并且满足对任意非根节点。整棵树的价值。。即所有点的深度和。

牛妹希望这棵树的W最小,请你告诉她,选择哪个点可以使W最小。
对于100%的数据,


做法:

有点诡异。
做法1:盲猜最优点在重心上。一遍求重心。从开始再一遍求深度和。做完。
做法2:换根dp。
表示以为整棵树的根的深度和。我们可以一遍求出以1为根的深度和。然后从1在一遍求出将根转移到子树上的深度和
转移:(size[v]表示子树v的大小)


代码

重心:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
const int inf = 0x3f3f3f3f;
vector<int> g[N];
int n, rt, son[N], size[N], dep[N], ans;
void getrt(int u, int p){
    size[u] = 1, son[u] = 0;
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        getrt(v, u);
        size[u] += size[v];
        son[u] = max(son[u], size[v]);
    }
    son[u] = max(son[u], n-size[u]);
    if (son[u] < son[rt]) rt = u;
}
void dfs(int u, int p){
    dep[u] = dep[p]+1;
    ans += dep[u];
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        dfs(v, u);
    }
}
int main(void){
    scanf("%d", &n);
    for (int i = 0; i < n-1; ++i){
        int u, v; scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    rt = 0, son[0] = inf;
    getrt(1, 1);
    dep[rt] = -1;
    dfs(rt, rt);
    printf("%d\n", ans);
    return 0;
}

换根dp:

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define debug(a) cout << #a ": " << a << endl
using namespace std;
typedef long long ll;
const int N = 1e6 + 7;
const int inf = 0x3f3f3f3f;
vector<int> g[N];
int n, dep[N], size[N], dp[N];
void dfs(int u, int p){
    if (u == p) dep[u] = 0;
    else dep[u] = dep[p]+1;
    size[u] = 1;
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        dfs(v, u);
        size[u] += size[v];
    }
}
void dfs1(int u, int p){
    for (int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if (v == p) continue;
        dp[v] = dp[u]-size[v]+(n-size[v]);
        dfs1(v, u);
    }
}
int main(void){
    scanf("%d", &n);
    for (int i = 0; i < n-1; ++i){
        int u, v; scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs(1, 1);
    for (int i = 1; i <= n; ++i) dp[1] += dep[i];
    dfs1(1, 1);
    int ans = inf;
    for (int i = 1; i <= n; ++i) ans = min(ans, dp[i]);
    printf("%d\n", ans);
    return 0;
}