Hard

Shortest Path in a Weighted TreeC++

Full explanation · Time O(nlogn) · Space O(n)

// Time:  O(nlogn)
// Space: O(n)

class BIT {
public:
    BIT(int n) : bit_(n + 1) {  // 0-indexed
    }
    
    void add(int i, int val) {
        ++i;
        for (; i < size(bit_); i += lower_bit(i)) {
            bit_[i] += val;
        }
    }

    int query(int i) const {
        ++i;
        int total = 0;
        for (; i > 0; i -= lower_bit(i)) {
            total += bit_[i];
        }
        return total;
    }

private:
    int lower_bit(int i) const {
        return i & -i;
    }
    
    vector<int> bit_;
};

// iterative dfs, fenwick tree
class Solution {
public:
    vector<int> treeQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        vector<vector<pair<int, int>>> adj(n);
        for (const auto& e : edges) {
            const int u = e[0] - 1, v = e[1] - 1, w = e[2];
            adj[u].emplace_back(v, w);
            adj[v].emplace_back(u, w);
        }
        
        const auto& iter_dfs = [&]() {
            vector<int> L(n), R(n), dist(n), lookup(n);
            int cnt = 0;
            vector<tuple<int, int, int, int>> stk = {{1, 0, -1, 0}};
            while (!empty(stk)) {
                const auto [step, u, p, d] = stk.back(); stk.pop_back();
                if (step == 1) {
                    L[u] = cnt++;
                    dist[u] = d;
                    stk.emplace_back(2, u, -1, -1);
                    for (const auto& [v, w] : adj[u]) {
                        if (v == p) {
                            continue;
                        }
                        lookup[v] = w;
                        stk.emplace_back(1, v, u, d + w);
                    }
                } else if (step == 2) {
                    R[u] = cnt;
                }
            }            
            return tuple(L, R, dist, lookup);
        };

        auto [L, R, dist, lookup] = iter_dfs();
        BIT bit(n);
        vector<int> result;
        for (const auto& q : queries) {
            if (q[0] == 1) {
                int u = q[1] - 1, v = q[2] - 1, w = q[3];
                if (L[u] > L[v]) {
                    swap(u, v);
                }
                const int diff = w - lookup[v];
                bit.add(L[v], diff);
                bit.add(R[v], -diff);
                lookup[v] = w;
            } else {
                const int x = q[1] - 1;
                result.emplace_back(dist[x] + bit.query(L[x]));
            }
        }
        return result;
    }
};

// Time:  O(nlogn)
// Space: O(n)
// dfs, fenwick tree
class Solution2 {
public:
    vector<int> treeQueries(int n, vector<vector<int>>& edges, vector<vector<int>>& queries) {
        vector<vector<pair<int, int>>> adj(n);
        for (const auto& e : edges) {
            const int u = e[0] - 1, v = e[1] - 1, w = e[2];
            adj[u].emplace_back(v, w);
            adj[v].emplace_back(u, w);
        }
        vector<int> L(n), R(n), dist(n), lookup(n);
        int cnt = 0;
        const function<void (int, int, int)> dfs = [&](int u, int p, int d) {
            L[u] = cnt++;
            dist[u] = d;
            for (const auto& [v, w] : adj[u]) {
                if (v == p) {
                    continue;
                }
                lookup[v] = w;
                dfs(v, u, d + w);
            }
            R[u] = cnt;
        };

        dfs(0, -1, 0);
        BIT bit(n);
        vector<int> result;
        for (const auto& q : queries) {
            if (q[0] == 1) {
                int u = q[1] - 1, v = q[2] - 1, w = q[3];
                if (L[u] > L[v]) {
                    swap(u, v);
                }
                const int diff = w - lookup[v];
                bit.add(L[v], diff);
                bit.add(R[v], -diff);
                lookup[v] = w;
            } else {
                const int x = q[1] - 1;
                result.emplace_back(dist[x] + bit.query(L[x]));
            }
        }
        return result;
    }
};