[POI2008] STA-Station(树形dp)
\(\Huge{[POI2008] STA-Station(树形dp)}\)
题目链接:[P3478 POI2008] STA-Station - 洛谷
题意
给定一个\(n\)个点的树,请求出一个结点,使得以这个结点为根时,所有结点的深度之和最大。
一个结点的深度之定义为该节点到根的简单路径上边的数量。
数据范围
- \(1 \le n \le 10^6\)
- \(1\le u,v \le n\)
思路
这是一道比较经典的树形dp问题。
假设以\(x\)点作为根节点,\(y\)是\(x\)的一个子节点;并令\(b[x]\)为x节点的子节点个数,\(res[x]\)为以\(x\)作为根节点时的深度之和,\(dep[x]\)为x的深度。
那么我们可以计算出,若将跟节点从\(x\)换为\(y\),那么可以得到:\(res[y]=res[x] - b[y] + (n - b[y])\)。
- \(-b[y]\)是因为其每个后代节点的度都减小\(1\)。
- \(+(n-b[y])\)是因为\(x\)的每个后代节点都增加\(1\)。
并且,我们首先设\(1\)为根节点,然后通过一次\(dfs\)求出\(dep[~],b[~]\);由每个点的深度我们可以求出\(res[1]\)。然后再从1开始\(dfs\)一次求出所有节点的\(res[~]\)。最后比较哪个节点的\(res[]\)值最大即可。
标程
#define int long long
const int N = 1e6 + 10;
int n, b[N], dep[N], res[N];
vector<int> a[N];
void dfs1(int x, int y) {
dep[x] = dep[y] + 1;
b[x] = 1;
for(auto i : a[x]) {
if(i == y) continue;
dfs1(i, x);
b[x] += b[i];
}
}
void dfs2(int x, int y) {
for(auto i : a[x]) {
if(i == y) continue;
res[i] = res[x] + b[1] - 2 * b[i];
dfs2(i, x);
}
}
void Solved() {
cin >> n;
for(int i = 1; i < n; i ++ ) {
int x, y; cin >> x >> y;
if(x == y) continue;
a[x].push_back(y); a[y].push_back(x);
}
dfs1(1, 0);
for(int i = 1; i <= n; i ++ ) res[1] += dep[i];
dfs2(1, 0);
int t = 1, mx = 0;
for(int i = 1; i <= n; i ++ ) {
if(res[i] > mx) t = i, mx = res[i];
}
cout << t << endl;
}

浙公网安备 33010602011771号