You are given a tree consisting of n vertices. A number is written on each vertex; the number on vertex i is equal to a_i.

Let's denote the function g(x, y) as the greatest common divisor of the numbers written on the vertices belonging to the simple path from vertex x to vertex y (including these two vertices). Also let's denote dist(x, y) as the number of vertices on the simple path between vertices x and y, including the endpoints. dist(x, x) = 1 for every vertex x.

Your task is calculate the maximum value of dist(x, y) among such pairs of vertices that g(x, y) > 1.

Input

The first line contains one integer n — the number of vertices (1 ≤ n ≤ 2 ⋅ 10^5).

The second line contains n integers a_1, a_2, ..., a_n (1 ≤ a_i ≤ 2 ⋅ 10^5) — the numbers written on vertices.

Then n - 1 lines follow, each containing two integers x and y (1 ≤ x, y ≤ n, x ≠ y) denoting an edge connecting vertex x with vertex y. It is guaranteed that these edges form a tree.

Output

If there is no pair of vertices x, y such that g(x, y) > 1, print 0. Otherwise print the maximum value of dist(x, y) among such pairs.

Examples

Input

3
2 3 4
1 2
2 3


Output

1


Input

3
2 3 4
1 3
2 3


Output

2


Input

3
1 1 1
1 2
2 3


Output

0
import static java.lang.Math.*;
import static java.util.Arrays.*;

import java.util.*;
import java.util.ArrayList;
import java.util.stream.*;

public class D {

	int Z = 200010;

	public Object solve () {
		int N = sc.nextInt();
		int [] A = sc.nextInts();
		int [][] E = dec(sc.nextInts(N-1));

		Permutation P = Permutation.random(N);
		A = P.permute(A);
		E = P.apply(E);

		if (maximum(A) == 1)
			return print(0);

		int [] L = leastPrimeDivisors(Z);
		@SuppressWarnings("unchecked")
		List<int[]> [] F = new List[Z];
		for (int [] e : E) {
			int g = (int) gcd(A[e[0]], A[e[1]]);
			for (int p = L[g]; g > 1; g /= p, p = L[g]) {
				if (F[p] == null)
					F[p] = new ArrayList<>();
				F[p].add(e);
			}
		}

		int res = 0;
		for (int p : rep(Z))
			res = max(res, calc(F[p]));
		return print(res + 1);
	}

	int calc (List<int[]> L) {
		if (L == null) return 0;
		if (L.size() == 1) return 1;
		int [][] E = compress(L.stream().map(e -> e.clone()).toArray(int[][]::new));
		int N = 1 + stream(E).mapToInt(e -> max(e[0], e[1])).max().getAsInt();
		int res = forestDiameter(graph(N, E));
		return res;
	}

	private static final boolean ONE_TEST_CASE = true;

	private static void init () {
	}

	private static final int INF = (int) 1e9 + 10;
	private static int [][] compress (int [][] E) {
		int N = E.length, C = 0;
		Map<Integer, Integer> M = new HashMap<>();
		for (int [] e : E)
			for (int j : e)
				if (!M.containsKey(j))
					M.put(j, C++);
		for (int i = 0; i < N; ++i)
			for (int j = 0; j < 2; ++j)
				E[i][j] = M.get(E[i][j]);
		return E;
	}
	private static int [][] dec (int [] ... E) { return dec(E, INF); }
	private static int [][] dec (int [][] E, int N) { for (int [] e : E) for (int i = 0; i < e.length && i < N; ++i) --e[i]; return E; }
	private static int forestDiameter(int [][] G) {
		int N = G.length;
		int [] Q = new int [N]; int fi = 0, la = 0;
		int [] D = new int [N]; fill(D, -1);
		int [] R = new int [N]; int K = 0;
		for (int i = 0; i < N; ++i)
			if (D[i] == -1) {
				D[Q[la++] = i] = 0;
				while (fi < la) {
					int q = Q[fi++];
					R[K] = q;
					for (int j : G[q])
						if (D[j] == -1)
							D[Q[la++] = j] = D[q] + 1;
				}
				++K;
			}
		fill(D, -1); fi = la = 0;
		for (int i = 0; i < K; ++i) {
			D[Q[la++] = R[i]] = 0;
			while (fi < la) {
				int q = Q[fi++];
				for (int j : G[q])
					if (D[j] == -1)
						D[Q[la++] = j] = D[q] + 1;
			}
		}
		int res = stream(D).max().getAsInt();
		return res;
	}
	private static long gcd (long x, long y) {
		if (x < 0) x = -x;
		if (y < 0) y = -y;
		while (y > 0) {
			long s = y, t = x % y;
			x = s; y = t;
		}
		return x;
	}
	private static int [][] graph (int N, int [][] E) {
		int [] D = new int [N];
		for (int [] e : E) {
			++D[e[0]];
			++D[e[1]];
		}
		int [][] res = new int [N][];
		for (int j = 0; j < N; ++j)
			res[j] = new int [D[j]];
		D = new int [N];
		for (int [] e : E) {
			int x = e[0], y = e[1];
			res[x][D[x]++] = y;
			res[y][D[y]++] = x;
		}
		return res;
	}
	private static int [] leastPrimeDivisors (int N) {
		int [] res = req(N);
		for (int j = 4; j <= N; j += 2)
			res[j] = 2;
		for (int p = 3; p*p <= N; p += 2)
			if (res[p] == p)
				for (int j = p*p; j <= N; j += 2*p)
					res[j] = min(res[j], p);
		return res;
	}
	private static int maximum (int ... A) { return stream(A).max().getAsInt(); }
	private static int [] rep (int N) { return rep(0, N); }
	private static int [] rep (int S, int T) { if (S >= T) return new int [0]; int [] res = new int [T-S]; for (int i = S; i < T; ++i) res[i-S] = i; return res; }
	private static int [] req (int N) { return req(0, N); }
	private static int [] req (int S, int T) { return rep(S, T+1); }
	private static class Permutation {
		final int [] P, Q;
		public Permutation (int [] P) {
			this.P = P; int N = P.length;
			Q = new int [N];
			for (int i = 0; i < N; ++i)
				Q[P[i]] = i;
		}
		public static Permutation random (int N) {
			Random rnd = new Random();
			int [] res = rep(N);
			for (int i = N-1; i > 0; --i) {
				int j = rnd.nextInt(i);
				int x = res[i], y = res[j];
				res[i] = y; res[j] = x;
			}
			return new Permutation(res);
		}
		public int [] permute (int [] A) {
			assert A.length == P.length;
			int N = P.length;
			int [] B = A.clone();
			for (int i = 0; i < N; ++i)
				A[P[i]] = B[i];
			return A;
		}
		public int [][] apply (int [][] A) {
			for (int i = 0; i < A.length; ++i)
				for (int j = 0; j < A[i].length; ++j)
					A[i][j] = P[A[i][j]];
			return A;
		}
	}
	//////////////////////////////////////////////////////////////////////////////////// OFF
	private static IOUtils.MyScanner sc = new IOUtils.MyScanner();
	private static Object print (Object o, Object ... A) { IOUtils.print(o, A); return null; }
	private static class IOUtils {
		public static class MyScanner {
			public String next () { newLine(); return line[index++]; }
			public int nextInt () { return Integer.parseInt(next()); }
			public String nextLine () { line = null; return readLine(); }
			public String [] nextStrings () { return split(nextLine()); }
			public int[] nextInts () { return nextStream().mapToInt(Integer::parseInt).toArray(); }
			public int[][] nextInts (int N) { return IntStream.range(0, N).mapToObj(i -> nextInts()).toArray(int[][]::new); }
			//////////////////////////////////////////////
			private boolean eol () { return index == line.length; }
			private String readLine () {
				try {
					return r.readLine();
				} catch (Exception e) {
					throw new Error (e);
				}
			}
			private final java.io.BufferedReader r;
			private MyScanner () { this(new java.io.BufferedReader(new java.io.InputStreamReader(System.in))); }
			private MyScanner (java.io.BufferedReader r) {
				try {
					this.r = r;
					while (!r.ready())
						Thread.sleep(1);
					start();
				} catch (Exception e) {
					throw new Error(e);
				}
			}
			private String [] line;
			private int index;
			private void newLine () {
				if (line == null || eol()) {
					line = split(readLine());
					index = 0;
				}
			}
			private java.util.stream.Stream<String> nextStream () { return java.util.Arrays.stream(nextStrings()); }
			private String [] split (String s) { return s.length() > 0 ? s.split(" ") : new String [0]; }
		}
		private static String build (Object o, Object ... A) { return buildDelim(" ", o, A); }
		private static String buildDelim (String delim, Object o, Object ... A) {
			StringBuilder b = new StringBuilder();
			append(b, o, delim);
			for (Object p : A)
				append(b, p, delim);
			return b.substring(delim.length());
		}
		//////////////////////////////////////////////////////////////////////////////////
		private static final java.text.DecimalFormat formatter = new java.text.DecimalFormat("#.#########");
		private static void start () { if (t == 0) t = millis(); }
		private static void append (java.util.function.Consumer<Object> f, java.util.function.Consumer<Object> g, final Object o) {
			if (o.getClass().isArray()) {
				int len = java.lang.reflect.Array.getLength(o);
				for (int i = 0; i < len; ++i)
					f.accept(java.lang.reflect.Array.get(o, i));
			}
			else if (o instanceof Iterable<?>)
				((Iterable<?>)o).forEach(f::accept);
			else
				g.accept(o instanceof Double ? formatter.format(o) : o);
		}
		private static void append (final StringBuilder b, Object o, final String delim) {
			append(x -> { append(b, x, delim); }, x -> b.append(delim).append(x), o);
		}
		private static java.io.PrintWriter pw = new java.io.PrintWriter(System.out);
		private static void print (Object o, Object ... A) {
			pw.println(build(o, A));
			if (DEBUG)
				pw.flush();
		}
		private static void err (Object o, Object ... A) { System.err.println(build(o, A)); }
		private static boolean DEBUG;
		private static void write (Object o) {
			err(o, '(', time(), ')');
			if (!DEBUG)
				pw.println(o);
		}
		private static void exit () {
			IOUtils.pw.close();
			System.out.flush();
			err("------------------");
			err(time());
			System.exit(0);
		}
		private static long t;
		private static long millis () { return System.currentTimeMillis(); }
		private static String time () { return "Time: " + (millis() - t) / 1000.0; }
		private static void run (int N) {
			try { DEBUG = System.getProperties().containsKey("DEBUG"); }
			catch (Throwable t) {}

			for (int n = 1; n <= N; ++n) {
				Object res = new D().solve();
				if (res != null)
					write("Case #" + n + ": " + build(res));
			}
			exit();
		}
	}
	////////////////////////////////////////////////////////////////////////////////////
	public static void main (String[] args) {
		init();
		int N = ONE_TEST_CASE ? 1 : sc.nextInt();
		IOUtils.run(N);
	}
}