#include <bits/stdc++.h>
using namespace std;
#define rep(i, a) for (int i = 0; i < (int)(a); i++)
#define sz(x) (int)(x).size()
#define pcnt __builtin_popcountll
typedef long long ll;
template<typename T>istream& operator>>(istream&i,vector<T>&v){rep(j,sz(v))i>>v[j];return i;}
template<typename T>string join(const vector<T>&v){stringstream s;rep(i,sz(v))s<<' '<<v[i];return s.str().substr(1);}
template<typename T>ostream& operator<<(ostream&o,const vector<T>&v){if(sz(v))o<<join(v);return o;}
template<typename T1,typename T2>istream& operator>>(istream&i,pair<T1,T2>&v){return i>>v.first>>v.second;}
template<typename T1,typename T2>ostream& operator<<(ostream&o,const pair<T1,T2>&v){return o<<v.first<<","<<v.second;}
template<typename T>bool mins(T& x,const T&y){if(x>y){x=y;return true;}else return false;}
template<typename T>bool maxs(T& x,const T&y){if(x<y){x=y;return true;}else return false;}
template<typename T>T dup(T x, T y){return (x+y-1)/y;}
template<typename T>ll suma(const vector<T>&a){ll res(0);for(auto&&x:a)res+=x;return res;}
int keta(ll n) { int ret = 0; while (n>0) { n/=10; ret++; } return ret; }

#ifdef _DEBUG
inline void dump() { cerr << endl; }
template <typename Head> void dump(Head &&head) { cerr << head; dump(); }
template <typename Head, typename... Tail> void dump(Head &&head, Tail &&... tail) { cerr << head << ", "; dump(forward<Tail>(tail)...); }
#define debug(...) do { cerr << __LINE__ << ":\t" << #__VA_ARGS__ << " = "; dump(__VA_ARGS__); } while (false)
#else
#define dump(...)
#define debug(...)
#endif

template <typename T> struct edge {
  int src, to;
  T cost, k;
  edge(int to, T cost, T k) : src(-1), to(to), cost(cost), k(k) {}
  edge &operator=(const int &x) {
    to = x;
    return *this;
  }
  operator int() const { return to; }
};
template <typename T> using Edges = vector<edge<T>>;
template <typename T> using WeightedGraph = vector<Edges<T>>;
using UnWeightedGraph = vector<vector<int>>;
template <typename T> using Matrix = vector<vector<T>>;

const ll LINF = 1LL << 60;
const int INF = 1001001001;

/////////////////////////////////////////////////////////////////////

vector<bool> flg(100010, false);
int n;
vector<int> c(100010);
vector<vector<int>> g(100010);
vector<int> dist(100010, INF);
vector<int> cnt(100010, 0);

void dfs(int p, int t)
{
  cnt[c[t]]++;
  if (cnt[c[t]] == 1) flg[t] = true;
  for (auto v:g[t]) {
    if (v == p) continue;
    if (dist[v] <= dist[t]+1) continue;
    mins(dist[v], dist[t]+1);
    dfs(t, v);
  }
  cnt[c[t]]--;
}

void solve()
{
  cin>>n;
  rep(i, n) cin>>c[i];
  rep(i, n-1) {
    int a,b; cin>>a>>b; a--; b--;
    g[a].push_back(b);
    g[b].push_back(a);
  }
  dist[0] = 0;
  dfs(-1, 0);
  rep(i, n) {
    if (flg[i]) cout << i+1 << "\n";
  }

}

int main()
{
  int t;
  t = 1;
  // cin>>t;
  while (t--) solve();

  return 0;
}

#include <bits/stdc++.h>
#include <variant>

#define rep2(i,k,n) for(i64 i=(i64)(k);i<(i64)(n);i++)
#define rep(i,n) rep2(i,0,n)
#define all(x) begin(x),end(x)
#ifdef ENV_LOCAL
#define dump if (1) cerr
#else
#define dump if (0) cerr
#endif

using namespace std;
using namespace std::string_literals;

using i32 = int32_t;
using i64 = int64_t;
using f64 = double;
using f80 = long double;
using vi32 = vector<i32>;
using vi64 = vector<i64>;

//using namespace harudake;

tuple<i32,i32,i32> tree_dp(const vector<vi32>& g, i32 th, i32 i, i32 p = -1) {
  i32 ans = 0;
  i32 deepest = 0;
  i32 cover = -1e8;
  for (auto&& to : g[i]) {
    if (to == p) continue;
    auto [cst, dep, cov] = tree_dp(g, th, to, i);
    ans += cst;
    cover = max(cover, cov-1);
    deepest = max(deepest, dep+1);
  }
  if (deepest <= cover) deepest = -1e8;
  if (deepest == th) {
    ++ans;
    deepest = -1e8;
    cover = th;
  }
  return make_tuple(ans, deepest, cover);
}

//void dfs(const vector<vi32>& g, vi32& d, i32 i, i32 p = -1) {
//  for (auto&& to : g[i]) {
//    if (to == p) continue;
//    d[to] = d[i] + 1;
//    dfs(g, d, to, i);
//  }
//}
//
//i32 get_to_put(const vector<vi32>& g, const vector<bool>& covered, i32 th) {
//  i32 n = size(g);
//  rep(i,n) {
//    if (!covered[i]) {
//      vi32 d(n, -1);
//      d[i] = 0;
//      dfs(g, d, i);
//      i32 mx = -1;
//      i32 mxj = 0;
//      rep(j,n) {
//        if (!covered[j]) {
//          if (d[j] > mx) {
//            mx = d[j];
//            mxj = j;
//          }
//        }
//      }
//      vi32 d2(n, -1);
//      d2[mxj] = 0;
//      dfs(g, d2, mxj);
//      mx = -1;
//      i32 j2 = 0;
//      rep(j,n) {
//        if (!covered[j]) {
//          if (d[j] > mx) {
//            mx = d[j];
//            j2 = j;
//          }
//        }
//      }
//      if (mx <= th) {
//        return j2;
//      }
//      vi32 d3(n, -1);
//      d3[j2] = 0;
//      dfs(g, d3, j2);
//      rep(j,n) {
//        if (d2[j] == th && d2[j] + d3[j] == d2[j2]) {
//          return j;
//        }
//      }
//      return -1;
//    }
//  }
//  return -1;
//}

bool check(const vector<vi32>& g, i32 k, i32 th) {
  auto [ans, deepest, cover] = tree_dp(g, th, 0);
  if (deepest >= 0) ++ans;
  return ans <= k;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  i32 n,k;
  cin>>n>>k;
  vector<vi32> g(n);
  rep(i,n-1) {
    i32 u,v;
    cin>>u>>v;
    --u;--v;
    g[u].push_back(v);
    g[v].push_back(u);
  }
  i32 lt = 0;
  i32 ge = n;
  while (ge - lt > 1) {
    i32 mid = (ge + lt) / 2;
    if (check(g, k, mid)) {
      ge = mid;
    } else {
      lt = mid;
    }
  }
  cout<<ge<<endl;
  return 0;
}
