#include <iostream>
#include <vector>
#include <string>
using namespace std;
const int MAXN = 100005;
vector<int> graph[MAXN];
int dp[MAXN][2]; // dp[i][0] = i无棋子时的最大移动次数, dp[i][1] = i有棋子时的最大移动次数
bool has_coin[MAXN]; // 标记每个节点是否有棋子
int n;
void dfs(int node, int parent) {
dp[node][0] = 0; // 初始化当前节点无棋子的最大移动次数为0
dp[node][1] = 0; // 初始化当前节点有棋子的最大移动次数为0
int max_without_coin = 0, max_with_coin = 0; // 子树中无棋子和有棋子的最大值
bool has_coin_here = has_coin[node]; // 当前节点是否有棋子
for (int child : graph[node]) {
if (child == parent) continue; // 避免回到父节点
dfs(child, node); // 递归计算子节点的dp值
max_without_coin = max(max_without_coin, dp[child][0]); // 更新无棋子的最大值
max_with_coin = max(max_with_coin, dp[child][1]); // 更新有棋子的最大值
}
// 更新当前节点的dp值
dp[node][0] = max_without_coin; // 当前节点无棋子时,取所有子树中无棋子的最大值
if (has_coin_here) { // 如果当前节点有棋子,则可以将其移到父节点(前提是父节点无棋子)
dp[node][1] = max_without_coin + 1; // 将当前节点的棋子移到父节点,并考虑其余无棋子的最大值+1
} else { // 当前节点无棋子,则考虑所有子树中有棋子的最大值(理论上不会发生,因为我们已经处理过)
dp[node][1] = max_with_coin; // 但理论上不会走到这里,因为我们只在有棋子时处理移动到父节点的情形
}
}
int main() {
cin >> n;
string s;
cin >> s;
for (int i = 1; i <= n; ++i) {
has_coin[i] = (s[i - 1] == '1'); // 读取每个节点的初始状态(是否有棋子)
}
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v; // 读取边信息并建立图结构
graph[u].push_back(v);
graph[v].push_back(u);
}
for (int i = 1; i <= n; ++i) { // 对每个节点作为根进行计算
dfs(i, 0