Typical tree recursion works. The key is: ANY node can be treated as the root, since it is about edge, not about node. This simplifies things a lot.

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_set>
using namespace std;

typedef long long long64;

struct Node
{
    Node() :val(0){}
    Node(unsigned v) : val(v){}
    long64 val;
    unordered_set<int> inx;
};

long64 ret = std::numeric_limits<unsigned>::max();

long64 go(vector<Node> &nodes, int root, long64 tsum)
{
    Node &n = nodes[root];

    long64 currsum = n.val;    
    for (int i : n.inx)
    {
        nodes[i].inx.erase(root);
        currsum += go(nodes, i, tsum);
    }
    
    ret = std::min(std::abs(tsum - 2 * currsum), ret);

    return currsum;
}

int main()
{
    int n; cin >> n;
    vector<Node> nodes(n);

    long64 sum = 0;
    for (int i = 0; i < n; i++)
    {
        unsigned v; cin >> v;
        sum += v;
        nodes[i].val = v;
    }

    for (int i = 0; i < n - 1; i++)
    {
        int pi, ci; cin >> pi >> ci;
        nodes[pi - 1].inx.insert(ci - 1);
        nodes[ci - 1].inx.insert(pi - 1);
    }

    go(nodes, 0, sum);
    cout << ret << endl;

    return 0;
}