HDU - 2196 Computer(二次扫描+换根法树形dp)

题目链接

题目大意

  求树上每个点到其他点的最大距离。

解题思路

  首先随便选择一个顶点作为根然后跑一遍dfs,记录每个顶点以其为根能到达的最大深度和次大深度,然后再跑一遍dfs,对于每个顶点,如果要到达一个距离最大的点,要么就是原来中的子树中的距离最大的点,要么就是经过父节点的某个点。

代码

#include<bits/stdc++.h>
#define endl '\n'
#define x first
#define y second
#define clr(arr,a) memset(arr, a, sizeof(arr))
#define IOS ios::sync_with_stdio(false)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
typedef pair<ll, int> Pll;
const double pi = acos(-1.0);
const double eps = 1e-8;
const int MOD = 1e9+7;
const int INF = 0x3f3f3f3f;
const int maxn = 1e4+10;
vector<P> e[maxn];
int n, dp[maxn][3], f[maxn];/*dp[u][0]是向下距离u最远的距离,
f[v]是向下距离u最远的顶点,dp[u][1]是向下的次远距离,dp[u][2]是经过父节点的最远距离*/
void dfs(int u) {
    for (auto v : e[u]) {
        dfs(v.y);
        if (dp[u][0]<v.x+dp[v.y][0]) {
            dp[u][1] = max(dp[u][1], dp[u][0]);
            dp[u][0] = v.x+dp[v.y][0];
            f[u] = v.y;
        }
        else dp[u][1] = max(dp[u][1], v.x+dp[v.y][0]);
    }
}
void dfs2(int u) {
    for (auto v : e[u]) {
        if (f[u]==v.y) dp[v.y][2] = max(dp[u][1], dp[u][2])+v.x;
        else dp[v.y][2] = max(dp[u][0], dp[u][2])+v.x;
        dfs2(v.y);
    }
}
int main(void) {
    while(cin >> n) {
        for (int i = 0; i<=n; ++i) e[i].clear(), f[i] = 0, dp[i][0] = dp[i][1] = dp[i][2] = 0;
        for (int i = 2, a, b; i<=n; ++i) {
            cin >> a >> b;
            e[a].push_back({b, i});
        }
        dfs(1);
        //for (int i = 1; i<=n; ++i) cout << dp[i][0] << ' '<< dp[i][1] << endl;
        dfs2(1);
        for (int i = 1; i<=n; ++i) cout << max(dp[i][0], dp[i][2]) << endl;
    }
    return 0;
}   
posted @ 2021-04-01 21:39  shuitiangong  阅读(132)  评论(0)    收藏  举报