#ifdef LOCAL
#include ".debug.hpp"
#else
#define debug(...) 42
#endif
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
using namespace std;
using ordered_set = tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update>;
const int MXN = 2e5 + 5;
vector<int> Tree[MXN];
int A[MXN];
bool isdead[MXN], mark[MXN];
set<int> root;
/*** Basic DSU template ***/
struct DSU {
int n;
vector<int> parent, component_size; // # parameters
DSU(int _n) { // # initial defining parameters
n = _n, parent.resize(n + 5), component_size.resize(n + 5);
for (int i = 1; i <= n; i++) parent[i] = i, component_size[i] = A[i];
}
inline int findpar(int node) { // # findpar function returns parent(ancestor) of node
if (node == parent[node]) return node;
return parent[node] = findpar(parent[node]);
}
inline bool unionset(int u, int v) { // # unionset function just unions two different components
u = findpar(u), v = findpar(v);
if (u == v) return false;
if (A[u] > component_size[v]) isdead[v] = true;
component_size[u] += component_size[v], parent[v] = u, Tree[u].push_back(v), root.erase(v);
return true;
}
};
void dfs(const int &node, bool deadpath) {
if (isdead[node]) deadpath = true;
mark[node] = !deadpath;
for (auto &child : Tree[node]) dfs(child, deadpath);
}
signed main() {
#ifndef VOID
cin.tie(nullptr)->sync_with_stdio(false);
#endif
int N, M; cin >> N >> M;
vector<vector<int>> adj(N + 1);
vector<array<int, 2>> seq; for (int i = 1; i <= N; i++) cin >> A[i], seq.push_back({A[i], i}), root.insert(i);
for (int i = 0, U, V; i < M; i++) cin >> U >> V, adj[U].push_back(V), adj[V].push_back(U);
sort(seq.begin(), seq.end());
vector<bool> active(N + 1);
DSU dsu(N);
for (auto &[w, node] : seq) {
active[node] = true;
for (auto &child : adj[node]) {
if (!active[child]) continue;
dsu.unionset(node, child);
}
}
for (auto &r : root) dfs(r, false);
for (int i = 1; i <= N; i++) cout << mark[i];
return 0;
}