最长乘积链 树形dp

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
using namespace std;
#define ll long long
const int N = 1e5+5;
ll d1[N]; // 存储从根节点到当前节点的最大路径长度
ll d2[N]; //从树的根节点出发到某个节点的第二长的路径的长度(次大路径长度)
int p1[N]; // 存储从根节点到当前节点最大路径的上一个节点
int p2[N]; // 存储从根节点到当前节点次大路径的上一个节点
ll up[N]; // 存储从当前节点向上走的最大路径长度
vector<pair<int,int>> e[N];

//用于找到从根节点到每个节点的最大路径长度,同时记录下最大路径上的前一个节点
void dfs1(int t,int f){
    for(auto &y:e[t]){
        if(y.first==f) continue;
        dfs1(y.first,t);
        if(d1[y.first] + y.second >= d1[t]){ // 如果从y.first出发的路径长度加上边的权值大于等于当前节点t的路径长度
            d2[t] = d1[t]; // 更新节点t的次大路径长度为最大路径长度
            p2[t] = p1[t]; // 更新节点t的次大路径的上一个节点为最大路径的上一个节点
            d1[t] = d1[y.first] + y.second; // 更新节点t的最大路径长度
            p1[t] = y.first; // 更新节点t的最大路径的上一个节点
        }
        else if(d1[y.first] + y.second > d2[t]){ // 如果从y.first出发的路径长度加上边的权值大于节点t的次大路径长度
            d2[t] = d1[y.first] + y.second; // 更新节点t的次大路径长度
            p2[t] = y.first; // 更新节点t的次大路径的上一个节点
        }
    }
}

void dfs2(int t,int f){
    for(auto &y:e[t]){
        if(y.first == f) continue;
        if(y.first == p1[t]){ // 如果边的另一端是节点t的最大路径的上一个节点
            up[y.first] = y.second + max(up[t],d2[t]); // 更新从y.first向上走的最大路径长度
        }
        else { // 如果边的另一端不是节点t的最大路径的上一个节点
            up[y.first] = y.second + max(up[t],d1[t]); // 更新从y.first向上走的最大路径长度
        }
        dfs2(y.first,t); // 递归调用dfs2
    }
}

int main()
{
    int n;
    cin >> n;
    for(int i = 1 ; i<=n-1 ;i++){
        int u,v,d;
        cin >> u >> v >> d;
        e[u].push_back({v,d});
        e[v].push_back({u,d});
    }
    dfs1(1,-1);
    dfs2(1,-1);
    ll ans = 0;
    for(int i = 1 ; i <= n ; i++){
        ll m = 0;
        m = max(d1[i]*up[i],d2[i]*d1[i]); // 计算从节点i出发的两条路径长度乘积的最大值
        ans = max(m,ans);
    }
    cout << ans ;
    return 0;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值