Problem:
Score : 600 points

Problem Statement

We have a tree with N vertices, whose i-th edge connects Vertex u_i and Vertex v_i.
Vertex i has an integer a_i written on it.
For every integer k from 1 through N, solve the following problem:

We will make a sequence by lining up the integers written on the vertices along the shortest path from Vertex 1 to Vertex k, in the order they appear. Find the length of the longest increasing subsequence of this sequence.

Here, the longest increasing subsequence of a sequence A of length L is the subsequence A_{i_1} , A_{i_2} , ... , A_{i_M} with the greatest possible value of M such that 1 \leq i_1 < i_2 < ... < i_M \leq L and A_{i_1} < A_{i_2} < ... < A_{i_M}.

Constraints

2 \leq N \leq 2 \times 10^5

1 \leq a_i \leq 10^9

1 \leq u_i , v_i \leq N

u_i \neq v_i

The given graph is a tree.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
a_1 a_2 ... a_N
u_1 v_1
u_2 v_2
:
u_{N-1} v_{N-1}

Output

Print N lines. The k-th line, print the length of the longest increasing subsequence of the sequence obtained from the shortest path from Vertex 1 to Vertex k.

Sample Input 1

10
1 2 5 3 4 6 7 3 2 4
1 2
2 3
3 4
4 5
3 6
6 7
1 8
8 9
9 10

Sample Output 1

1
2
3
3
4
4
5
2
2
3

For example, the sequence A obtained from the shortest path from Vertex 1 to Vertex 5 is 1,2,5,3,4. Its longest increasing subsequence is A_1, A_2, A_4, A_5, with the length of 4.

Solution in C++ (GCC 9.2.1) (judge verdict: Accepted)

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <vector>
#include <string>

using namespace std;

#define LL long long

const int dx[4] = {1, -1, 0, 0};
const int dy[4] = {0, 0, 1, -1};

LL mod(LL x, LL md) {
	return ((x % md) + md) % md;
}

class Mint {
public:
	static LL md;
	LL x;
	Mint(LL _x) {
		x = mod(_x, md);
	}
	Mint(const Mint &y) {
		x = mod(y.x, md);
	}
};

void MintMyExgcd(LL a, LL b, LL &x, LL &y) {
	// solve equation ax + by = 1 (mod m)
	LL md = Mint::md;
	if (b == 0) {
		y = 0;
		x = 1;
		return ;
	}
	MintMyExgcd(b, a % b, x, y);
	LL t = y;
	y = mod(x - (a / b) * y, md);
	x = t;
}

LL MintNY(LL x) {
	if (x == 0) {
		return 1;
	}
	LL md = Mint::md;
	LL a, b;
	MintMyExgcd(x, md, a, b);
	while (a < 0) {
		a += md;
	}
	return a;
}

/* LL gcd(LL a, LL b) {
	if (b == 0) {
		return a;
	}
	return gcd(b, a % b);
} */

Mint operator+(Mint a, Mint b) {
	return Mint(mod(a.x + b.x, Mint::md));
}
Mint operator-(Mint a, Mint b) {
	return Mint(mod(a.x - b.x, Mint::md));
}
Mint operator*(Mint a, Mint b) {
	return Mint(mod(a.x * b.x, Mint::md));
}
Mint operator/(Mint a, Mint b) {
	Mint c = Mint(MintNY(b.x));
	return Mint(mod(a.x * c.x, Mint::md));
}

Mint operator-(Mint a) {
	return Mint(-a.x);
}
bool operator==(Mint a, Mint b) {
	return a.x == b.x;
}
bool operator!=(Mint a, Mint b) {
	return a.x != b.x;
}
bool operator>(Mint a, Mint b) {
	return a.x > b.x;
}
bool operator<(Mint a, Mint b) {
	return a.x < b.x;
}
bool operator>=(Mint a, Mint b) {
	return a.x >= b.x;
}
bool operator<=(Mint a, Mint b) {
	return a.x <= b.x;
}

void operator+=(Mint &a, Mint b) {
	a = a + b;
}
void operator-=(Mint &a, Mint b) {
	a = a - b;
}
void operator*=(Mint &a, Mint b) {
	a = a * b;
}
void operator/=(Mint &a, Mint b) {
	a = a / b;
}

ostream& operator<<(ostream &out, Mint a) {
	out << a.x;
	return out;
}

istream& operator>>(istream &in, Mint &a) {
	in >> a.x;
	return in;
}

Mint factorial(LL n) {
	if (n == 0) {
		return Mint(1);
	}
	Mint res = 1;
	for (LL i = 1; i <= n; ++i) {
		res *= i;
	}
	return res;
}
Mint multiRange(LL s, LL t) {
	Mint res = 1;
	for (LL i = s; i <= t; ++i) {
		res *= i;
	}
	return res;
}

Mint getC(LL n, LL k) {
	if (n - k < k) {
		return getC(n, n - k);
	}
	return multiRange(n - k + 1, n) / factorial(k);
}

Mint getA(LL n, LL k) {
	return multiRange(n - k + 1, n);
}

Mint countNonNegativeDivision(LL n, LL k) {
	return getC(n + k - 1, k - 1);
}
Mint countPositiveDivision(LL n, LL k) {
	if (n < k) {
		return 0;
	}
	if (k <= 0) {
		return 0;
	}
	return getC(n - 1, k - 1);
}
Mint quickMod(Mint a, LL b) {
	Mint res = 1;
	while (b > 0) {
		if (b % 2) {
			res *= a;
		}
		a *= a;
		b /= 2;
	}
	return res;
}

LL Mint::md = 1000000007;

class Edge {
public:
	int t, nxt;
	bool isDir;
	Edge(int _t, int _nxt, bool _isDir = false): t(_t), nxt(_nxt), isDir(_isDir) {}
};
class Node {
	public:
	Node *left, *right;
	int res;
	Node(int _res): res(_res) {
		left = right = NULL;
	}
};

class ChairManTree {
public:
	int n;
	vector<Node *> v;
	int cur;
	Node *buildTree(int l, int r) {
		// cout << "build " << endl;
		if (l == r) {
			return new Node(0);
		}
		Node *nd = new Node(0);
		int mid = (l + r) / 2;
		nd->left = buildTree(l, mid);
		nd->right = buildTree(mid + 1, r);
		return nd;
	}
	ChairManTree(int _n): n(_n) {
		v.clear();
		v.push_back(buildTree(0, n - 1));
		cur = 0;
	}
	void push(int x, int val) {
		// printf("push(%d, %d)\n", x, val);
		Node *oldR = v[cur];
		Node *newR = new Node(max(v[cur]->res, val));
		Node *rt = newR;
		int l = 0, r = n - 1;
		while (l < r) {
			// cout << "l = " << l << ", r = " << r << endl;
			int mid = (l + r) / 2;
			if (x > mid) {
				newR->left = oldR->left;
				newR->right = new Node(max(oldR->right->res, val));
				newR = newR->right;
				oldR = oldR->right;
				l = mid + 1;
			}
			else {
				newR->right = oldR->right;
				newR->left = new Node(max(oldR->left->res, val));
				newR = newR->left;
				oldR = oldR->left;
				r = mid;
			}
		}
		v.push_back(rt);
		cur += 1;
	}
	int ask(Node *rr, int l, int r, int x) {
		// printf("ask(l = %d, r = %d, x = %d)\n", l, r, x);
		if (r < x) {
			return rr->res;
		}
		if (l == r) {
			return 0;
		}
		int mid = (l + r) / 2;
		if (x > mid) {
			// cout << rr->left->res << endl;
			// cout << rr->right->res << endl;
			return max(rr->left->res, ask(rr->right, mid + 1, r, x));
		}
		else {
			// cout << rr->left->res << endl;
			return ask(rr->left, l, mid, x);
		}
	}
	int query(int x) {
		// printf("query(%d)\n", x);
		Node *r = v[cur];
		return ask(r, 0, n - 1, x) + 1;
	}
	void pop() {
		// printf("pop()\n");
		v.pop_back();
		cur -= 1;
	}
};

class Nums {
	public:
	int idx, x;
	Nums(int _idx, int _x): x(_x), idx(_idx) {}
};

bool cmp(const Nums &a, const Nums &b) {
	return a.x < b.x;
}

vector<int> discretize(vector<int> &x, int &maxCur) {
	// cout << endl;
	vector<Nums> a;
	a.clear();
	for (int i = 0; i < x.size(); ++i) {
		a.push_back(Nums(i, x[i]));
	}
	sort(a.begin(), a.end(), cmp);
	int cur = 0;
	vector<int> res(a.size());
	for (int i = 0; i < a.size(); ++i) {
		// cout << a[i].idx << ' ' << a[i].x << endl;
		if (i != 0 && a[i].x != a[i - 1].x) {
			++cur;
		}
		res[a[i].idx] = cur;
	}
	maxCur = cur;
	return res;
}

class Tree {
public:
	int n;
	vector<Edge> e;
	int edgeN;
	vector<int> h;
	vector<int> s, f;
	vector<int> c;
	vector<int> res;
	int root;
	vector<bool> vis;
	vector<int> a;
	ChairManTree *cmt;
	int maxCur;
	int ans;

	void addEdge(int u, int v) {
		// printf("addEdge(%d, %d)", u, v);
		e.push_back(Edge(v, h[u]));
		h[u] = edgeN++;
		e.push_back(Edge(u, h[v]));
		h[v] = edgeN++;
	}

	void initDFS(int r) {
		// cout << "dfs " << r << endl;
		s[r] = 1;
		vis[r] = true;
		for (int p = h[r]; p != -1; p = e[p].nxt) {
			int t = e[p].t;
			// printf("edge between (%d, %d)\n", r, t);
			if (vis[t]) {
				e[p].isDir = false;
				continue;
			}
			e[p].isDir = true;
			f[t] = r;
			initDFS(t);
			s[r] += s[t];
		}
	}

	void initialize(int _root = 0) {
		root = _root;
		for (int i = 0; i < n; ++i) {
			s.push_back(0);
			f.push_back(-1);
			vis.push_back(false);
		}
		initDFS(root);
	}

	void printVector(vector<int> &x, string name) {
		cout << name << ": ";
		for (int i = 0; i < x.size(); ++i) {
			cout << x[i] << ' ';
		}
		cout << endl;
	}

	void checkOutput() {
		// printVector(s, "s");
		// printVector(f, "f");
		// printVector(h, "h");
		// cout << "root = " << root << endl;
	}

	Tree() {
		scanf("%d", &n);
		edgeN = 0;

		h.clear();
		for (int i = 0; i < n; ++i) {
			h.push_back(-1);
			c.push_back(0);
		}
		maxCur = 0;
		for (int i = 0; i < n; ++i) {
			scanf("%d", &c[i]);
			maxCur = max(maxCur, c[i]);
			// c[i] -= 1;
		}
		// cout << "load c" << endl;

		c = discretize(c, maxCur);
		// cout << "discretized" << endl;
		// for (int i = 0; i < c.size(); ++i) {
		// 	cout << c[i] << ' ';

		// }
		// cout << endl;

		int u, v;
		for (int i = 0; i < n - 1; ++i) {
			scanf("%d%d", &u, &v);
			addEdge(u - 1, v - 1);
		}
		// cout << "edges added" << endl;


		initialize();
		// checkOutput();
		// cout << "initialized" << endl;
		res = vector<int>(n + 1);
		cmt = new ChairManTree(maxCur + 1);
	}

	void workDFS(int r) {
		res[r] = cmt->query(c[r]);
		cmt->push(c[r], res[r]);
		
		int ansTmp = ans;
		ans = max(ans, res[r]);
		res[r] = ans;
		for (int p = h[r]; p != -1; p = e[p].nxt) {
			if (e[p].isDir) {
				workDFS(e[p].t);
			}
		}
		cmt->pop();
		ans = ansTmp;
	}

	void work() {
		ans = 0;
		workDFS(0);

		for (int i = 0; i < n; ++i) {
			printf("%d\n", res[i]);
		}
	}
	~Tree() {
	}
};

int main() {
	Tree t;
	t.work();
	return 0;
}