#include <iostream>
#include <algorithm>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <list>
#include <set>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <random>
#include <complex>
#include <assert.h>

using namespace std;
typedef long long ll;
#define endl '\n'

template<typename T>
inline bool chmin(T& x, T a) {
	if (x >= a) { x = a; return true; }
	return false;
}

template<typename T>
inline bool chmax(T& x, T a) {
	if (x <= a) { x = a; return true; }
	return false;
}

///////////////// 各種設定 /////////////////

#define USE_SUBTREE_SIZE
// #define USE_LCA

class TreeClass {// 木の入力を受け取る
public:
	TreeClass() {
		N = 0, root = 0;
		next = NULL;
#ifdef USE_LCA
		parent = NULL;
#endif
	}
	TreeClass(int _N, int _root = 0) {
		next = NULL;
#ifdef USE_LCA
		parent = NULL;
#endif
		activate(_N, _root);
	}

	~TreeClass() {
		if (next != NULL) { delete[] next; }
#ifdef USE_LCA
		if (parent != NULL) { delete[] parent; }
#endif
	}

	void activate(int n, int _root = 0) {// 頂点数nのグラフを初期化する。
		N = n;
		root = _root;

		weight.resize(N);
		for (int i = 0; i < N; i++) { weight[i] = 1; }

		back.resize(N);
		if (next != NULL) { delete[] next; }
		next = new unordered_map<int, int>[N];
		edge.clear();

		depth.clear();
		depth.resize(N);

#ifdef USE_SUBTREE_SIZE
		subtree_size.clear();
		subtree_size.resize(N);
#endif
#ifdef USE_LCA
		if (parent != NULL) { delete[] parent; }
		parent = new vector<int>[N];
		for (int i = 0; i < N; i++) { parent[i].clear(); }
#endif
	}
	inline void setNodeWeight(int n, ll weight) {// n番のノードの重みをweightに設定
		this->weight[n] = weight;
	}

	inline int getEdgeIndex(int x, int y) {// 辺の組からエッジの番号を得る
		if (next[x].find(y) != next[x].end()) {
			return next[x][y];
		}
		return -1;
	}
	inline void addEdge(int x, int y, ll _weight = 1) {// エッジ追加
		int M = (int)edge.size();
		edge.push_back({ {x,y}, _weight });

		next[x].insert({ y, M });
		next[y].insert({ x, M });

		if (edge.size() == N - 1) {
			initProcess();

#ifdef USE_SUBTREE_SIZE
			dfs(&TreeClass::dfs_processSubtreeSize);
#endif
#ifdef USE_LCA
			bfs(&TreeClass::bfs_processDoubling);
#endif
		}
	}

#ifdef USE_LCA
	inline int LCA(int a, int b) {
		int d = min(depth[a], depth[b]);

		if (depth[a] > d) {
			int k = depth[a] - d;
			for (int i = 0; k > 0; i++) {
				if ((1 << i) & k) {
					k -= (1 << i);
					a = parent[a][i];
				}
			}
		}
		if (depth[b] > d) {
			int k = depth[b] - d;
			for (int i = 0; k > 0; i++) {
				if ((1 << i) & k) {
					k -= (1 << i);
					b = parent[b][i];
				}
			}
		}
		if (a == b) { return a; }

		for (int k = parent[a].size() - 1; k >= 0; k--) {
			if (k < parent[a].size() && k < parent[b].size() && (parent[a][k] != parent[b][k])) {
				a = parent[a][k];
				b = parent[b][k];
			}
		}
		return parent[a][0];
	}
#endif

	inline void changeRoot(int r, bool ProcessDoublingFlag = true) {
		assert(r >= 0 && r < N);
		root = r;
		initProcess();

#ifdef USE_SUBTREE_SIZE
		dfs(&TreeClass::dfs_processSubtreeSize);
#endif
#ifdef USE_LCA
		if (ProcessDoublingFlag)  bfs(&TreeClass::bfs_processDoubling);
#endif
	}

	inline pair<int, vector<int>> getDiameter_and_Center() {
		int r0 = root;
		int d1 = -1, k1 = -1;
		for (int i = 0; i < N; i++) {
			if (chmax(d1, depth[i])) {
				k1 = i;
			}
		}
		changeRoot(k1, false);

		int d2 = -1, k2 = -1;
		for (int i = 0; i < N; i++) {
			if (chmax(d2, depth[i])) {
				k2 = i;
			}
		}
		int i = k2;
		if (d2 % 2 == 0) {
			while (1) {
				int j = back[i].first;
				if (depth[j] == d2 / 2) {
					changeRoot(r0, false);
					return { d2, { j } };
				}
				i = j;
			}
		}
		else {
			while (1) {
				int j = back[i].first;
				if (depth[j] == d2 / 2) {
					changeRoot(r0, false);
					return { d2, { i, j } };
				}
				i = j;
			}
		}
		return { d2, { root } };
	}
private:
	inline void initProcess() {// bfsの順番を取得すると同時に、根からの深さを得る。
		for (int i = 0; i < N; i++) {
			depth[i] = -1;
			back[i] = { -1, -1 };
		}

		queue<pair<int, int>> q; q.push({ root, 0 });

		bfs_order.clear();

		while (q.size() > 0) {
			int n = q.front().first;
			int d = q.front().second;
			q.pop();

			bfs_order.push_back(n);

			depth[n] = d;

			auto _erase = next[n].end();// 根に向かう辺
			for (auto itr = next[n].begin(); itr != next[n].end(); itr++) {
				int m = itr->first;

				if (depth[m] == -1) {
					q.push({ m, d + 1 });
				}
				else {
					_erase = itr;
					back[n] = { itr->first, itr->second };
				}
			}
			if (_erase != next[n].end()) {
				next[n].erase(_erase);
			}
		}
	}
	inline void dfs(void (TreeClass::* dfs_process)(int n)) {
		for (int i = N - 1; i >= 0; i--) {
			(this->*dfs_process)(bfs_order[i]);
		}
	}
	inline void bfs(void (TreeClass::* bfs_process)(int n)) {
		for (int i = 0; i < N; i++) {
			(this->*bfs_process)(bfs_order[i]);
		}
	}

#ifdef USE_SUBTREE_SIZE
	void dfs_processSubtreeSize(int n) {// 部分木のサイズを得る
		subtree_size[n] = 1;
		for (auto itr = next[n].begin(); itr != next[n].end(); itr++) {
			subtree_size[n] += subtree_size[itr->first];
		}
	}
#endif
#ifdef USE_LCA
	void bfs_processDoubling(int n) {// ダブリング
		parent[n].clear();
		if (n == root) { return; }

		parent[n].push_back(back[n].first);
		for (int k = 0; depth[n] >= (1 << (k + 1)); k++) {
			parent[n].push_back(parent[parent[n][k]][k]);
		}
	}
#endif

public:
	int N, root;
	vector<ll> weight;// ノードの重み

	vector<pair<pair<int, int>, ll>> edge;// エッジ(頂点ペアと重み)

	vector<pair<int, int>> back;// 根に近いノードと、エッジ番号
	unordered_map<int, int>* next;// 各ノードからの行き先とエッジ番号

	vector<int> depth;// 根から見た深さ
	vector<int> bfs_order;// bfsの際に訪れる順番(dfsは逆順)

#ifdef USE_SUBTREE_SIZE
	vector<int> subtree_size;// 部分木のサイズ
#endif
#ifdef USE_LCA
	vector<int>* parent;//1番目、2番目、4番目、8番目...の親
#endif
};

inline void dfs(TreeClass& T, void (*dfs_process)(TreeClass& T, int n)) {
	for (int i = T.N - 1; i >= 0; i--) {
		dfs_process(T, T.bfs_order[i]);
	}
}
inline void bfs(TreeClass& T, void (*bfs_process)(TreeClass& T, int n)) {
	for (int i = 0; i < T.N; i++) {
		bfs_process(T, T.bfs_order[i]);
	}
}

vector<int> color;
vector<int> sempai;
vector<int> rem;
vector<int> sum;
vector<ll> ans;

void initorder_main(TreeClass& T, int n) {
	int c = color[n];
	int stemp = sempai[c];

	int r = T.subtree_size[n];
	for (auto itr = T.next[n].begin(); itr != T.next[n].end(); itr++) {
		sempai[c] = itr->first;
		initorder_main(T, itr->first);
		r -= rem[itr->first];
	}
	sempai[c] = stemp;

	if (sempai[c] != -1) {
		rem[sempai[c]] += T.subtree_size[n];
	}
	sum[c] += r;

	if (n != T.root) {
		int m = T.back[n].first;
		int c2 = color[m];

		ll k = T.subtree_size[n] - rem[n];
		ans[c2] += k * (k - 1) / 2;
	}
}
void initorder(TreeClass& T) {
	initorder_main(T, T.root);
}

int main() {
	ios::sync_with_stdio(false);
	std::cin.tie(0);

	ll N; cin >> N;

	TreeClass T(N);

	ans.resize(N);
	sum.resize(N);
	color.resize(N);
	sempai.resize(N);
	rem.resize(N);

	for (int i = 0; i < N; i++) {
		ans[i] = N;
	}

	for (int i = 0; i < N; i++) {
		int c; cin >> c;
		color[i] = c - 1;
		sempai[i] = -1;
		rem[i] = 0;
		sum[i] = 0;
		ans[c - 1]--;
	}

	for (int i = 1; i < N; i++) {
		int a, b; cin >> a >> b;
		T.addEdge(a - 1, b - 1);
	}

	initorder(T);

	ll M = N * (N - 1) / 2 + N;

	for (int i = 0; i < N; i++) {
		ll k = N - sum[i];
		ans[i] += k * (k - 1) / 2;
		cout << M - ans[i] << endl;
	}

	return 0;
}

Measured memory_bytes: 62868