思路:用 dp[u][1] 表示选取了u与他父节点之间的边,dp[u][0] 表示未选取。首先,假设 j 是 u 的子节点,那么无论是否选取 u 与父节点的边,均可以加上 dp[j][0] 的情况。此外,若不选 u 与父节点之间的边,那么就可以选择 u 的子节点 j 与 u 之间的边,所以 dp[u][0] 需要加上 u 与子节点之间最长的边。

状态转移:dp[u][0] += sum(dp[j][0]) + max(dp[j][1] - dp[j][0]);

                dp[u][1] += sum(dp[j][0]);(dp[u][1]初始赋值为u与父节点之间边的权值)

AC代码

#include<bits/stdc++.h>
using namespace std;
using std::bitset;
typedef pair<int, int> pll;

#define int long long
const int N = 400010;
int e[N], ne[N], h[N],w[N], idx;
int dp[N][2];

void add(int a, int b, int c)
{
    e[idx] = b;
    ne[idx] = h[a];
    w[idx] = c;
    h[a] = idx++;
}

void dfs(int u, int fa, int wi)
{
    dp[u][1] = wi;
    int d = 0;
    for(int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if(j == fa)continue;
        dfs(j, u, w[i]);
        d = max(d, dp[j][1] - dp[j][0]);
        dp[u][0] += dp[j][0];
        dp[u][1] += dp[j][0];
    }
    dp[u][0] += d; 
}

void solve()
{
    int n;
    cin >> n;
    int m = n - 1;
    memset(h, -1, sizeof h);
    while(m--)
    {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c);
        add(b, a, c);
    }
    dfs(1, 0, 0);
    cout << dp[1][0] << endl;
}

signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    int t;
    t = 1;
    //t = read(t);
    while (t--)
    {
        solve();
    }

}