题目链接
https://www.luogu.com.cn/problem/P3478
思路
对于 n = 1 e 6 n=1e6 n=1e6,我们考虑换根dp。
定义 f [ u ] f[u] f[u]表示以 u u u为根的子树中,所有节点的深度之和。定义 d p [ u ] dp[u] dp[u]表示整棵树以 u u u为根时,所有节点的深度之和。定义 s i z [ u ] siz[u] siz[u]表示以 u u u为根的子树中节点的个数。
对于 f f f的状态转移方程为: f [ u ] = f [ j ] + s i z [ j ] ( j ∈ s o n ( u ) ) f[u] = f[j]+siz[j](j \in son(u)) f[u]=f[j]+siz[j](j∈son(u))。
如上图所示,对于 d p dp dp数组,当根从 1 1 1号节点转移到 2 2 2号节点时:
我们令 1 1 1号节点为 u u u, 2 2 2号节点为 j j j。从 1 1 1号节点的父节点转移到 1 1 1号节点的贡献为 s u m sum sum。
则传递到 j j j的贡献为: ( f [ u ] − f [ j ] − s i z [ j ] ) + ( n − s i z [ j ] ) + s u m (f[u] - f[j] - siz[j]) + (n - siz[j]) + sum (f[u]−f[j]−siz[j])+(n−siz[j])+sum。
状态转移方程为: d p [ u ] = f [ u ] + s u m dp[u] = f[u] + sum dp[u]=f[u]+sum(其中, s u m sum sum为转移到节点 u u u上的贡献)。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int>pii;
const int N = 1e6 + 5, M = 1e6 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n;
int siz[N], f[N], dp[N];
vector<int>mp[N];
void dfs(int u, int fu, int deep)
{siz[u] = 1;f[u] = 0;for (int j : mp[u]){if (j == fu)continue;dfs(j, u, deep + 1);siz[u] += siz[j];f[u] += (f[j] + siz[j]);}
}
void dfs1(int u, int fu, int sum)
{dp[u] = f[u] + sum;for (int j : mp[u]){if (j == fu)continue;dfs1(j, u, sum + f[u] - f[j] - siz[j] + n - siz[j]);}
}
void solve()
{cin >> n;for (int i = 1, u, v; i < n; i++){cin >> u >> v;mp[u].push_back(v);mp[v].push_back(u);}dfs(1, -1, 0);dfs1(1, -1, 0);int idx = 1, maxx = 0;for (int i = 1; i <= n; i++){if (dp[i] > maxx){maxx = dp[i];idx = i;}}cout << idx << endl;
}signed main()
{ios::sync_with_stdio(false);cin.tie(0), cout.tie(0);int test = 1;// cin >> test;for (int i = 1; i <= test; i++){solve();}return 0;
}