#include <bits/stdc++.h>
#define REP(i, n) for (int i = 0; i < n; i++)
#define REPR(i, n) for (int i = n - 1; i >= 0; i--)
#define FOR(i, m, n) for (int i = m; i <= n; i++)
#define FORR(i, m, n) for (int i = m; i >= n; i--)
#define SORT(v, n) sort(v, v + n)
using namespace std;
using ll = long long;
using vll = vector<ll>;
using vvll = vector<vector<ll>>;
using P = pair<ll, ll>;
using Graph = vector<vector<int>>;
using Edge = pair<int, ll>;
const int MAX = 100000;
const ll INF = 1LL << 60;

struct UnionFind
{
    vector<int> par, siz;
    UnionFind(int n) : par(n, -1), siz(n, 1) {} // 連結成分サイズの配列。最初はみんな根、サイズ1。

    // 木の根を求める
    int root(int x)
    {
        if (par[x] < 0)
            return x; // 根
        else
            return root(par[x]); // 経路圧縮(O(logn)になる)
    }

    // xとyの属する集合を併合。小さい方をくっつける。
    bool unite(int x, int y)
    {
        // 先に経路圧縮。根どうしを結合する。
        x = root(x);
        y = root(y);
        if (x == y)
            return false;
        if (siz[x] < siz[y])
            swap(x, y); // sizの大きい方を根に
        par[y] = x;     //yの根はxに。葉はrootの値が正になる。
        siz[x] += siz[y];
        return true;
    }

    //xとyが同じ集合に属するか判定
    bool issame(int x, int y) { return root(x) == root(y); }

    //集合のサイズを返す
    int size(int x) { return siz[root(x)]; }
};

int main()
{
    // cin高速化
    cin.tie(0);
    ios::sync_with_stdio(false);
    int n, m;
    cin >> n >> m;
    vll a(n), b(n);
    REP(i, n)
    cin >> a[i];
    REP(i, n)
    cin >> b[i];

    // 無向グラフを連結
    UnionFind uf(n);
    REP(i, m)
    {
        int x, y;
        cin >> x >> y;
        --x, --y;
        uf.unite(x, y);
    }

    // 連結部分の総和
    vll sa(n, 0), sb(n, 0);
    REP(v, n)
    {
        int r = uf.root(v);
        sa[r] += a[v], sb[r] += b[v];
    }
    bool ans = true;
    // 任意の頂点について、根の総和が一致するか確認
    REP(v, n)
    {
        int r = uf.root(v);
        if (sa[r] != sb[r])
            ans = false;
    }
    if (ans)
        cout << "Yes"
             << "\n";
    else
        cout << "No"
             << "\n";
    return 0;
}
#include <bits/stdc++.h>
using namespace std;

#define REP(i,n) for(int i=0, i##_len=(n); i<i##_len; ++i)
#define all(x) (x).begin(),(x).end()
using ll = long long;
using P = pair<ll, ll>;
const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, -1, 0, 1};
string char_to_string(char val) {
  return string(1, val);
}
int char_to_int(char val) {
  return val - '0';
}
char inverse_char(char c) {
  if(isupper(c)) return tolower(c);
  else return toupper(c);
}
template<class T> inline bool chmin(T& a, T b) {
  if (a > b) {
    a = b;
    return true;
  }
  return false;
}
template<class T> inline bool chmax(T& a, T b) {
  if (a < b) {
    a = b;
    return true;
  }
  return false;
}
struct edge {
  ll to, cost;
};

vector<ll> C;

vector<vector<ll>> tree;
vector<ll> res; // その頂点にたどり着いたか？
vector<ll> ans; // 答え

map<ll, ll> _tmp;
void dfs(ll pnt) {
  res[pnt] = 1; _tmp[C[pnt]]++;
  if(_tmp[C[pnt]] == 1) ans.push_back(pnt);
  for(int i = 0; i < tree[pnt].size(); ++i) {
    if(res[tree[pnt][i]] == 1) continue;
    dfs(tree[pnt][i]);
  }
  _tmp[C[pnt]]--;
}

int main() {
  ll N; cin >> N;
  C.resize(N); REP(i, N) cin >> C[i];
  vector<ll> A(N - 1), B(N - 1);
  REP(i, N - 1) {
    cin >> A[i] >> B[i];
    --A[i]; --B[i];
  }
  tree.resize(N); res.resize(N);
  REP(i, N - 1) {
    tree[A[i]].push_back(B[i]);
    tree[B[i]].push_back(A[i]);
  }
  dfs(0); sort(all(ans));
  REP(i, ans.size()) cout << ans[i] + 1 << endl;
}