/ SeriousOJ /

Record Detail

Accepted


  
# Status Time Cost Memory Cost
#1 Accepted 1ms 532.0 KiB
#2 Accepted 25ms 532.0 KiB
#3 Accepted 23ms 532.0 KiB
#4 Accepted 4ms 832.0 KiB
#5 Accepted 23ms 532.0 KiB
#6 Accepted 120ms 1.52 MiB
#7 Accepted 91ms 1.641 MiB
#8 Accepted 117ms 1.691 MiB
#9 Accepted 92ms 3.84 MiB
#10 Accepted 69ms 23.27 MiB
#11 Accepted 67ms 23.312 MiB
#12 Accepted 100ms 23.324 MiB
#13 Accepted 56ms 9.27 MiB
#14 Accepted 151ms 32.219 MiB
#15 Accepted 152ms 25.289 MiB
#16 Accepted 96ms 1.875 MiB

Code

#include <iostream>
#include <vector>
#include <algorithm>

using namespace std;

// Use a large enough value for infinity.
// Sum of weights can be up to 2e5*1e9=2e14.
// Cycle weight can be positive or negative.
const long long INF = 4e18; 

struct Edge {
    int to;
    int cost;
};

int N;
vector<long long> W;
vector<vector<Edge>> adj;
vector<long long> dp_down1; // max pathval(v, u) for v in subtree(u)
vector<long long> dp_down2; // max pathval(v, u) for v in subtree(u), v != u
long long max_cycle_weight;

// pathval(x, u) = S_W(x,u) - 2*S_C(x,u)
// Helper relation: for x in subtree of v, where v is child of u:
// pathval(x, u) = pathval(x, v) + W[u] - 2*cost(u,v)

void dfs(int u, int p) {
    // Post-order traversal: first visit children
    for (const auto& edge : adj[u]) {
        int v = edge.to;
        if (v == p) continue;
        dfs(v, u);
    }
    
    // --- DP calculation for node u ---
    long long max_child_term = -INF;
    for (const auto& edge : adj[u]) {
        int v = edge.to;
        if (v == p) continue;
        max_child_term = max(max_child_term, dp_down1[v] - 2LL * edge.cost);
    }

    if (max_child_term != -INF) {
        dp_down2[u] = W[u] + max_child_term;
    } else { // u is a leaf
        dp_down2[u] = -INF;
    }
    dp_down1[u] = max(W[u], dp_down2[u]);
    
    // --- Update global answer for paths with LCA = u ---
    
    // Case 1: Endpoints in different child subtrees
    vector<long long> child_branch_vals;
    for (const auto& edge : adj[u]) {
        int v = edge.to;
        if (v == p) continue;
        // value of max path from u down into v's branch
        child_branch_vals.push_back(dp_down1[v] - 2LL * edge.cost + W[u]);
    }

    if (child_branch_vals.size() >= 2) {
        sort(child_branch_vals.rbegin(), child_branch_vals.rend());
        max_cycle_weight = max(max_cycle_weight, child_branch_vals[0] + child_branch_vals[1] - W[u]);
    }

    // Case 2: One endpoint is u, other is in a grandchild's subtree
    vector<long long> grandchild_branch_vals;
    for (const auto& edge : adj[u]) {
        int v = edge.to;
        if (v == p) continue;
        if (dp_down2[v] != -INF) {
             grandchild_branch_vals.push_back(dp_down2[v] - 2LL * edge.cost + W[u]);
        }
    }
    
    if (!grandchild_branch_vals.empty()) {
        sort(grandchild_branch_vals.rbegin(), grandchild_branch_vals.rend());
        max_cycle_weight = max(max_cycle_weight, grandchild_branch_vals[0]);
    }
}

void solve() {
    cin >> N;

    W.assign(N + 1, 0);
    for (int i = 1; i <= N; ++i) {
        cin >> W[i];
    }

    adj.assign(N + 1, vector<Edge>());
    for (int i = 0; i < N - 1; ++i) {
        int u, v, c;
        cin >> u >> v >> c;
        adj[u].push_back({v, c});
        adj[v].push_back({u, c});
    }

    dp_down1.assign(N + 1, 0);
    dp_down2.assign(N + 1, 0);
    
    // Cycle weights can be negative, so initialize with a very small number.
    max_cycle_weight = -INF;

    // Start DFS from an arbitrary root, e.g., node 1.
    // The logic is independent of the choice of root for the DFS traversal.
    dfs(1, 0);

    cout << max_cycle_weight << endl;
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}

Information

Submit By
Type
Submission
Problem
P1205 E. Make Cycle in Tree
Language
C++17 (G++ 13.2.0)
Submit At
2025-07-14 18:24:30
Judged At
2025-07-14 18:24:30
Judged By
Score
100
Total Time
152ms
Peak Memory
32.219 MiB