Generous sponsors of the olympiad in which Chloe and Vladik took part allowed all the participants to choose a prize for them on their own. Christmas is coming, so sponsors decided to decorate the Christmas tree with their prizes. 

They took n prizes for the contestants and wrote on each of them a unique id (integer from 1 to n). A gift i is characterized by integer ai — pleasantness of the gift. The pleasantness of the gift can be positive, negative or zero. Sponsors placed the gift 1 on the top of the tree. All the other gifts hung on a rope tied to some other gift so that each gift hung on the first gift, possibly with a sequence of ropes and another gifts. Formally, the gifts formed a rooted tree with n vertices.

The prize-giving procedure goes in the following way: the participants come to the tree one after another, choose any of the remaining gifts and cut the rope this prize hang on. Note that all the ropes which were used to hang other prizes on the chosen one are not cut. So the contestant gets the chosen gift as well as the all the gifts that hang on it, possibly with a sequence of ropes and another gifts.

Our friends, Chloe and Vladik, shared the first place on the olympiad and they will choose prizes at the same time! To keep themselves from fighting, they decided to choose two different gifts so that the sets of the gifts that hang on them with a sequence of ropes and another gifts don't intersect. In other words, there shouldn't be any gift that hang both on the gift chosen by Chloe and on the gift chosen by Vladik. From all of the possible variants they will choose such pair of prizes that the sum of pleasantness of all the gifts that they will take after cutting the ropes is as large as possible.

Print the maximum sum of pleasantness that Vladik and Chloe can get. If it is impossible for them to choose the gifts without fighting, print Impossible.

Input

The first line contains a single integer n (1 ≤ n ≤ 2·105) — the number of gifts.

The next line contains n integers a1, a2, ..., an ( - 109 ≤ ai ≤ 109) — the pleasantness of the gifts.

The next (n - 1) lines contain two numbers each. The i-th of these lines contains integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) — the description of the tree's edges. It means that gifts with numbers ui and vi are connected to each other with a rope. The gifts' ids in the description of the ropes can be given in arbirtary order: vi hangs on ui or ui hangs on vi. 

It is guaranteed that all the gifts hang on the first gift, possibly with a sequence of ropes and another gifts.

Output

If it is possible for Chloe and Vladik to choose prizes without fighting, print single integer — the maximum possible sum of pleasantness they can get together.

Otherwise print Impossible.

Examples

Input

8
0 5 -1 4 3 2 6 5
1 2
2 4
2 5
1 3
3 6
6 7
6 8


Output

25

Input

4
1 -5 1 1
1 2
1 4
2 3


Output

2

Input

1
-1


Output

Impossible
import java.io.*;
import java.math.BigInteger;
import java.util.*;

/**
 *
 * @author Saju
 *
 */

public class Main {

	private static final long INF = (long) (1e15);
	
	public static void main(String[] args) {

		InputReader in = new InputReader(System.in);
		PrintWriter out = new PrintWriter(System.out);

/*



*/
		
		int n = in.nextInt();
		long costs[] = new long[n];
		long subtreeCost[] = new long[n];
		long maxSubtreeCost[] = new long[n];
		for(int i = 0; i < n; i++){
			costs[i] = in.nextLong();
			subtreeCost[i] = costs[i];
		}
		List<Integer> adj[] = new ArrayList[n];
		for(int i = 0; i < n; i++){
			adj[i] = new ArrayList<Integer>();
		}
		
		for(int i = 0; i < n - 1; i++){
			int u = in.nextInt();
			int v = in.nextInt();
			u--;
			v--;
			adj[u].add(v);
			adj[v].add(u);
		}
		dfs(0, -1, adj, costs, subtreeCost, maxSubtreeCost);
		
//		System.out.println(Arrays.toString(costs));
//		System.out.println(Arrays.toString(subtreeCost));
		
		if(result <= -INF){
			out.println("Impossible");
		}
		else{
			out.println(result);
		}
		
		out.flush();
		out.close();
		System.exit(0);
	}
	
	private static long result = -INF;
	
	private static void dfs(int u, int p, List<Integer>[] adj, long[] costs, long[] subtreeCost, long[] maxSubtreeCost) {
		
		maxSubtreeCost[u] = -INF;
		Vector<Long> vector = new Vector<>();
		for(int v : adj[u]){
			if(v != p){
				dfs(v, u, adj, costs, subtreeCost, maxSubtreeCost);
				subtreeCost[u] += subtreeCost[v];
				maxSubtreeCost[u] = max(maxSubtreeCost[u], maxSubtreeCost[v]);
				vector.add(maxSubtreeCost[v]);
			}
		}
		maxSubtreeCost[u] = max(maxSubtreeCost[u], subtreeCost[u]);
		Collections.sort(vector);
		int sz = vector.size();
		long big1 = -INF * 4;
		long big2 = -INF * 4;
		
		if(vector.size() > 1){
			big2 = vector.get(sz - 2);
			big1 = vector.get(sz - 1);
		}
		else if(vector.size() > 0){
			big1 = vector.get(sz - 1);
		}
		
		result = max(result, big1 + big2);
		
	}
	

	private static class Pair{
		int x;
		int y;
		Pair(int x, int y){
			this.x = x;
			this.y = y;
		}
	}
	
	private static int log(int x, int base) {
		return (int) (Math.log(x) / Math.log(base));
	}

	private static long max(long a, long b) {
		if (a >= b) {
			return a;
		}
		return b;
	}
	
	private static int max(int a, int b) {
		if (a >= b) {
			return a;
		}
		return b;
	}

	private static long min(long a, long b) {
		if (a <= b) {
			return a;
		}
		return b;
	}
	
	private static long gcd(long a, long b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}
	
	private static int gcd(int a, int b) {
		if (b == 0) {
			return a;
		}
		return gcd(b, a % b);
	}

	private static long bigMod(long n, long k, long m) {

		long ans = 1;
		while (k > 0) {
			if ((k & 1) == 1) {
				ans = (ans * n) % m;
			}
			n = (n * n) % m;
			k >>= 1;
		}
		return ans;
	}

	/*
	 * Returns an iterator pointing to the first element in the range [first,
	 * last] which does not compare less than val.
	 * 
	 */
	private static int lowerBoundNew(long[] arr, long num) {
		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			if (arr[mid] > num) {
				end = mid - 1;
			} else if (arr[mid] < num) {
				start = mid + 1;
			} else {
				while (mid >= 0 && arr[mid] == num) {
					mid--;
				}
				return mid + 1;
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	/*
	 * upper_bound() is a standard library function in C++ defined in the header
	 * . It returns an iterator pointing to the first element in the range
	 * [first, last) that is greater than value, or last if no such element is
	 * found
	 * 
	 */
	private static int upperBoundNew(long[] arr, long num) {

		int start = 0;
		int end = arr.length - 1;
		int index = 0;
		int len = arr.length;
		int mid = 0;
		while (true) {
			if (start > end) {
				break;
			}
			mid = (start + end) / 2;
			if (arr[mid] > num) {
				end = mid - 1;
			} else if (arr[mid] < num) {
				start = mid + 1;
			} else {
				while (mid < len && arr[mid] == num) {
					mid++;
				}
				if (mid == len - 1 && arr[mid] == num) {
					return mid + 1;
				} else {
					return mid;
				}
			}
		}
		if (arr[mid] < num) {
			return mid + 1;
		}
		return mid;
	}

	private static class InputReader {
		public BufferedReader reader;
		public StringTokenizer tokenizer;

		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}

		public String next() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());

				}
			} catch (IOException e) {
				return null;
			}
			return tokenizer.nextToken();
		}

		public String nextLine() {
			String line = null;
			try {
				tokenizer = null;
				line = reader.readLine();
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
			return line;
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public double nextDouble() {
			return Double.parseDouble(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public boolean hasNext() {
			try {
				while (tokenizer == null || !tokenizer.hasMoreTokens()) {
					tokenizer = new StringTokenizer(reader.readLine());
				}
			} catch (Exception e) {
				return false;
			}
			return true;
		}
	}
	
	private class TrieTusar {

	    private class TrieNode {
	        Map<Character, TrieNode> children;
	        boolean endOfWord;
	        public TrieNode() {
	            children = new HashMap<>();
	            endOfWord = false;
	        }
	    }

	    private final TrieNode root;
	    public TrieTusar() {
	        root = new TrieNode();
	    }
	    
	    public void test(String[] args){
	    	
	    
	    	TrieTusar ttr = new TrieTusar();
	    	ttr.insert("baggers");
	    	ttr.insert("beggars");
	    	ttr.insert("in");
	    	ttr.insert("the");
	    	ttr.insert("blowed");
	    	ttr.insert("bowled");
	    	ttr.insert("barn");
	    	ttr.insert("bran");

	    	
	    }

	    /**
	     * Iterative implementation of insert into trie
	     */
	    public void insert(String word) {
	        TrieNode current = root;
	        for (int i = 0; i < word.length(); i++) {
	            char ch = word.charAt(i);
	            TrieNode node = current.children.get(ch);
	            if (node == null) {
	                node = new TrieNode();
	                current.children.put(ch, node);
	            }
	           
	            current = node;
	          
	        }
	       
	        //mark the current nodes endOfWord as true
	        current.endOfWord = true;
	    }

	    /**
	     * Recursive implementation of insert into trie
	     */
	    public void insertRecursive(String word) {
	        insertRecursive(root, word, 0);
	    }


	    private void insertRecursive(TrieNode current, String word, int index) {
	        if (index == word.length()) {
	            //if end of word is reached then mark endOfWord as true on current node
	            current.endOfWord = true;
	            return;
	        }
	        char ch = word.charAt(index);
	        TrieNode node = current.children.get(ch);

	        //if node does not exists in map then create one and put it into map
	        if (node == null) {
	            node = new TrieNode();
	            current.children.put(ch, node);
	        }
	        insertRecursive(node, word, index + 1);
	    }

	    /**
	     * Iterative implementation of search into trie.
	     */
	    public boolean search(String word) {
	        TrieNode current = root;
	        for (int i = 0; i < word.length(); i++) {
	            char ch = word.charAt(i);
	            TrieNode node = current.children.get(ch);
	            //if node does not exist for given char then return false
	            if (node == null) {
	                return false;
	            }
	            current = node;
	        }
	        //return true of current's endOfWord is true else return false.
	        return current.endOfWord;
	    }

	    /**
	     * Recursive implementation of search into trie.
	     */
	    public boolean searchRecursive(String word) {
	        return searchRecursive(root, word, 0);
	    }
	    private boolean searchRecursive(TrieNode current, String word, int index) {
	        if (index == word.length()) {
	            //return true of current's endOfWord is true else return false.
	            return current.endOfWord;
	        }
	        char ch = word.charAt(index);
	        TrieNode node = current.children.get(ch);
	        //if node does not exist for given char then return false
	        if (node == null) {
	            return false;
	        }
	        return searchRecursive(node, word, index + 1);
	    }

	    /**
	     * Delete word from trie.
	     */
	    public void delete(String word) {
	        delete(root, word, 0);
	    }

	    /**
	     * Returns true if parent should delete the mapping
	     */
	    private boolean delete(TrieNode current, String word, int index) {
	        if (index == word.length()) {
	            //when end of word is reached only delete if currrent.endOfWord is true.
	            if (!current.endOfWord) {
	                return false;
	            }
	            current.endOfWord = false;
	            //if current has no other mapping then return true
	            return current.children.size() == 0;
	        }
	        char ch = word.charAt(index);
	        TrieNode node = current.children.get(ch);
	        if (node == null) {
	            return false;
	        }
	        boolean shouldDeleteCurrentNode = delete(node, word, index + 1);

	        //if true is returned then delete the mapping of character and trienode reference from map.
	        if (shouldDeleteCurrentNode) {
	            current.children.remove(ch);
	            //return true if no mappings are left in the map.
	            return current.children.size() == 0;
	        }
	        return false;
	    }
	    
	    
	}
}