【题解】P1131 [ZJOI2007] 时态同步

P1131 [ZJOI2007] 时态同步

题目传送门

题目大意:
给你一棵带边权的树,求出使所有叶节点到根节点的路程相同的最少操作数(每次操作边权加 1 )

STEP 1.

看到这个题目后,我们就可以联想到一棵树了,具体来讲:

\(n\) 个节点只有 \(n-1\) 条边 \(\implies\)
激发器 \(\implies\) 根节点
终止节点 \(\implies\) 叶节点
电流通过导线的时间 \(\implies\) 边权

尝试使用 树形DP 完成。

STEP 2.

\(f(i)\) 表示从第 \(i\) 个节点发出电流,所有 \(i\) 的子树的叶节点到 \(i\) 路程相同的最少需要操作的次数,

\(num(i)\) 表示当从第 \(i\) 个节点发出电流,所有 \(i\) 的子树的叶节点到 \(i\) 路程相同的操作次数达到最少时,从第 \(i\) 个节点到达叶子节点需要的时间。

经过分析可得,\(num(i)\)(所有 \(i\) 的子树的叶节点到 \(i\) 路程相同的操作次数达到最少时,从第 \(i\) 个节点到达叶子节点需要的时间) 就是其孩子的 \(num\) 加上孩子与其的距离的最大值,具体来说:

\(num(i)=\max\limits_{j∈children_i}num(j)+len(j)\)

(这里的 \(len(x)\)\(x\) 到其父节点的距离)

\(f(i)\) 则为其所有子节点的子树里达到时态同步最少需要操作的次数之和 加上到达叶子节点需要的时间减去所有子树的 \(num(j)\) 加上与其子树的距离这两项的和,具体来说:

\(f(i)=\sum\limits_{j∈children_i}dp(j)+\sum\limits_{j∈children_i}num(i)-(num(j)+len(j))\)

(这里的 \(len(x)\)\(x\) 到其父节点的距离)

需要注意的是,这里的 \(num(x)\) 需要先预处理完毕后再求 \(f(x)\)

最后的答案就是 \(f(root)\),这里的 \(root\) 就是激发器(根节点)。

STEP 3.

将视角转向数据范围:

  • 对于 \(40\%\) 的数据,\(1\le N\le 1000\)
  • 对于 \(100\%\) 的数据,\(1\le N\le 5\times 10^5\)
    对于所有的数据,\(1\le t_e\le 10^6\)

显然,由于 \(t_e\le 10^6\) ,存 \(f(x)\)\(num(x)\) 时,需要开 \(\large{long\space long}\)

STEP 4.

个人存图只爱用 vector 了(带边权就用 vector+pair)

代码(凭良心复制)
#include<bits/stdc++.h>
using namespace std;
#define ll long long

int n, rt, a, b, t;
vector<pair<int, int>> tr[500005];
ll dp[500005], num[500005];

void dfs1(int i, int fa) {
    num[i] = 0;
    for(auto it : tr[i]) {
        int j = it.first;
        int dis = it.second;
        if(j == fa) continue;
        dfs1(j, i);
        num[i] = max(num[i], num[j] + dis);
    }
}

void dfs2(int i, int fa) {
    dp[i] = 0;
    for(auto it : tr[i]) {
        int j = it.first;
        int dis = it.second;
        if(j == fa) continue;
        dfs2(j, i);
        dp[i] += dp[j] + (num[i] - (num[j] + dis));
    }
}

int main() {
    cin >> n >> rt;
    for(int i = 1; i < n; i++) {
        cin >> a >> b >> t;
        tr[a].push_back({b, t});
        tr[b].push_back({a, t});
    }
    
    dfs1(rt, 0);
    dfs2(rt, 0);
    
    cout << dp[rt];
    return 0;
}
posted @ 2025-10-07 09:12  yangmengcheng1103  阅读(2)  评论(0)    收藏  举报