鱼香rose'Blog

[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;
}
posted @ 2026-01-15 21:51  鱼香_rose  阅读(0)  评论(0)    收藏  举报