import std.stdio, std.string, std.conv;
import std.range, std.algorithm, std.array, std.typecons, std.container;
import std.math, std.numeric, core.bitop;

enum inf = 1_001_001_001;
enum infl = 1_001_001_001_001_001_001L;
enum mod = 1_000_000_007L;


void main() {
    int n;
    scan(n);
    auto a = readln.split.to!(long[]);
    auto adj = new int[][](n, 0);
    foreach (i ; 0 .. n - 1) {
        int ui, vi;
        scan(ui, vi);
        ui--, vi--;
        adj[ui] ~= vi;
        adj[vi] ~= ui;
    }

    auto chil = new int[][](n, 0);
    auto cnt = new int[](n);

    int cntDfs(int v, int p) {
        cnt[v] = 1;
        foreach (u ; adj[v]) {
            if (u == p) continue;
            chil[v] ~= u;
            cnt[v] += cntDfs(u, v);
        }
        return cnt[v];
    }

    cntDfs(0, -1);

    // dp(0, v, k) = (vをrootとしたsubtreeにおいて、CCがk個で、vを含むCC以外は条件を満たすときの、vを含むCCの総和の最小)
    // dp(1, v, k) = (..., vを含むCC以外は全て条件を満たし、vを含むCCは全て正のときの、vを含むCCの総和の最小)
    auto dp = new long[][][](2, n + 1, n + 1);
    auto dp2 = new long[][][](2, n + 1, n + 1);
    fillAll(dp, infl);
    fillAll(dp2, infl);

    void dfs(int v) {
        if (chil[v].empty) {
            dp[0][v][1] = a[v];
            if (a[v] > 0) dp[1][v][1] = a[v];
            return;
        }

        foreach (u ; chil[v]) {
            dfs(u);
        }
        
        auto m = chil[v].length.to!int;

        foreach (b ; 0 .. 2) {
            foreach (i ; 0 .. m + 1) {
                foreach (k ; 0 .. cnt[v] + 1) {
                    dp2[b][i][k] = infl;
                }
            }
        }

        dp2[0][0][1] = a[v];
        if (a[v] > 0) dp2[1][0][1] = a[v];


        debug {
            writeln("chil[v]:", chil[v]);
            writeln(dp2[0][0]);
            writeln(dp2[1][0]);
        }

        foreach (i ; 1 .. m + 1) {
            auto u = chil[v][i - 1];

            
            foreach (k ; 1 .. cnt[v] + 1) {
                foreach (b ; 0 .. (a[v] > 0 ? 2 : 1)) {
                    foreach (j ; 1 .. min(k, cnt[u]) + 1) {
                        // 繋がないときは切ったところが条件を満たすか確かめる
                        if (dp[0][u][j] < 0 || dp[1][u][j] < infl) {
                            dp2[b][i][k] = min(dp2[b][i][k], dp2[b][i-1][k-j]);
                        }

                        // 繋ぐときはどうでもいい
                        if (j > 0) {
                            dp2[b][i][k] = min(dp2[b][i][k], dp2[b][i-1][k+1-j] + dp[1][u][j]);
                            if (b == 0) dp2[b][i][k] = min(dp2[b][i][k], dp2[b][i-1][k+1-j] + dp[0][u][j]);
                        }
                    }
                }
            }

            debug {
                foreach (b ; 0 .. 2) {
                    writefln("v = %d, b = %b, i = %d, %s", v, b, i, dp2[b][i]);
                }
                writeln;
            }

        }

        foreach (k ; 1 .. cnt[v] + 1) {
            dp[0][v][k] = dp2[0][m][k];
            dp[1][v][k] = dp2[1][m][k];
        }
    }

    dfs(0);

    debug {
        foreach (v; 0 .. n) {
            foreach (b ; 0 .. 2) {
                writefln("v = %d, b = %b, %s", v, b, dp[b][v]);
            }
        }
    }

    int ans;

    foreach (i ; 1 .. n + 1) {
        if (dp[0][0][i] < 0 || dp[1][0][i] < inf) {
            ans = i;
            break;
        }
    }

    ans--;

    writeln(ans);
}





void scan(T...)(ref T args) {
    import std.stdio : readln;
    import std.algorithm : splitter;
    import std.conv : to;
    import std.range.primitives;

    auto line = readln().splitter();
    foreach (ref arg; args) {
        arg = line.front.to!(typeof(arg));
        line.popFront();
    }
    assert(line.empty);
}

void fillAll(R, T)(ref R arr, T value) {
    static if (is(typeof(arr[] = value))) {
        arr[] = value;
    }
    else {
        foreach (ref e; arr) {
            fillAll(e, value);
        }
    }
}
