#include <iostream>
#include <vector>
#include <set>
#include <map>
#include <algorithm>

using namespace std;

// Struktura przechowująca stan pojedynczej składowej w grafie
struct Component {
    vector<int> q;                          // Kolejka wierzchołków do przetworzenia
    vector<int> nodes;                      // Wierzchołki należące do tej składowej
    set<int> keys;                          // Zabrane klucze
    map<int, vector<int>> blocked;          // Krawędzie zablokowane: wymagany_klucz -> lista_celów
};

int n, m;
vector<int> r;
vector<vector<pair<int, int>>> adj;
vector<int> parent_node;
vector<int> state; // 0: NIEODWIEDZONE, 1: AKTYWNE (w stosie), 2: ZAKOŃCZONE
vector<bool> is_sink;
vector<int> sz;
vector<bool> expanded;
vector<Component*> comps;

// Struktura Zbiorów Rozłącznych (DSU) z kompresją ścieżki
int find_set(int v) {
    if (v == parent_node[v]) return v;
    return parent_node[v] = find_set(parent_node[v]);
}

// Funkcja łącząca dwie składowe (Small-To-Large Merging)
int merge_components(int u, int v) {
    u = find_set(u);
    v = find_set(v);
    if (u == v) return u;

    int size_u = comps[u]->nodes.size() + comps[u]->keys.size() + comps[u]->blocked.size();
    int size_v = comps[v]->nodes.size() + comps[v]->keys.size() + comps[v]->blocked.size();

    // Zapewniamy, że dołączamy mniejszy do większego (dla wydajności O(N log^2 N))
    if (size_u < size_v) {
        swap(u, v);
    }

    for (int node : comps[v]->nodes) {
        comps[u]->nodes.push_back(node);
    }

    for (int key : comps[v]->keys) {
        if (comps[u]->keys.find(key) == comps[u]->keys.end()) {
            comps[u]->keys.insert(key);
            auto it = comps[u]->blocked.find(key);
            if (it != comps[u]->blocked.end()) {
                for (int nxt : it->second) comps[u]->q.push_back(nxt);
                comps[u]->blocked.erase(it);
            }
        }
    }

    for (auto& pair : comps[v]->blocked) {
        int key = pair.first;
        if (comps[u]->keys.find(key) != comps[u]->keys.end()) {
            for (int nxt : pair.second) comps[u]->q.push_back(nxt);
        } else {
            auto& u_vec = comps[u]->blocked[key];
            if (u_vec.empty()) {
                u_vec = move(pair.second);
            } else {
                u_vec.insert(u_vec.end(), pair.second.begin(), pair.second.end());
            }
        }
    }

    for (int q_item : comps[v]->q) {
        comps[u]->q.push_back(q_item);
    }

    parent_node[v] = u;
    delete comps[v]; // Zwalniamy pamięć
    comps[v] = nullptr;

    return u;
}

int main() {
    // Optymalizacja wejścia/wyjścia
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    if (!(cin >> n >> m)) return 0;

    r.resize(n);
    for (int i = 0; i < n; ++i) cin >> r[i];

    adj.resize(n);
    for (int i = 0; i < m; ++i) {
        int u, v, c;
        cin >> u >> v >> c;
        adj[u].push_back({v, c});
        adj[v].push_back({u, c});
    }

    parent_node.resize(n);
    for (int i = 0; i < n; ++i) parent_node[i] = i;

    state.assign(n, 0);
    is_sink.assign(n, false);
    sz.assign(n, 0);
    expanded.assign(n, false);
    comps.assign(n, nullptr);

    vector<int> active_stack;

    for (int i = 0; i < n; ++i) {
        if (state[find_set(i)] == 0) {
            int root = i;
            comps[root] = new Component();
            comps[root]->q.push_back(i);
            comps[root]->nodes.push_back(i);
            state[root] = 1;
            active_stack.push_back(root);

            while (!active_stack.empty()) {
                int curr = active_stack.back();
                bool paused = false;

                while (!comps[curr]->q.empty()) {
                    int u = comps[curr]->q.back();
                    comps[curr]->q.pop_back();

                    int root_u = find_set(u);
                    if (root_u != curr) {
                        if (state[root_u] == 0) {
                            // Znaleziono nową, nieodwiedzoną składową
                            comps[curr]->q.push_back(u); 
                            
                            comps[u] = new Component();
                            comps[u]->q.push_back(u);
                            comps[u]->nodes.push_back(u);
                            state[u] = 1;
                            active_stack.push_back(u);
                            paused = true;
                            break;
                        } else if (state[root_u] == 1) {
                            // Znaleziono cykl aktywnych składowych
                            comps[curr]->q.push_back(u); 
                            
                            vector<int> cycle_comps;
                            while (true) {
                                int top = active_stack.back();
                                active_stack.pop_back();
                                cycle_comps.push_back(top);
                                if (top == root_u) break;
                            }
                            int new_root = cycle_comps[0];
                            for (size_t k = 1; k < cycle_comps.size(); ++k) {
                                new_root = merge_components(new_root, cycle_comps[k]);
                            }
                            active_stack.push_back(new_root);
                            paused = true;
                            break;
                        } else if (state[root_u] == 2) {
                            // Znaleziono dojście do przetworzonego grafu (ta składowa nie jest ujściem)
                            state[curr] = 2;
                            is_sink[curr] = false;
                            active_stack.pop_back();
                            delete comps[curr];
                            comps[curr] = nullptr;
                            paused = true;
                            break;
                        }
                    } else {
                        // Ekspansja własnego węzła
                        if (!expanded[u]) {
                            expanded[u] = true;
                            int key = r[u];
                            if (comps[curr]->keys.find(key) == comps[curr]->keys.end()) {
                                comps[curr]->keys.insert(key);
                                auto it = comps[curr]->blocked.find(key);
                                if (it != comps[curr]->blocked.end()) {
                                    for (int nxt : it->second) comps[curr]->q.push_back(nxt);
                                    comps[curr]->blocked.erase(it);
                                }
                            }
                            for (auto& edge : adj[u]) {
                                int v = edge.first;
                                int req_key = edge.second;
                                if (comps[curr]->keys.find(req_key) != comps[curr]->keys.end()) {
                                    comps[curr]->q.push_back(v);
                                } else {
                                    comps[curr]->blocked[req_key].push_back(v);
                                }
                            }
                        }
                    }
                }

                if (!paused) {
                    // Składowa w całości eksplorowana (jest ujściem!)
                    state[curr] = 2;
                    is_sink[curr] = true;
                    sz[curr] = comps[curr]->nodes.size();
                    active_stack.pop_back();
                    delete comps[curr];
                    comps[curr] = nullptr;
                }
            }
        }
    }

    // Znajdowanie najmniejszego rozmiaru ujścia
    int min_p = 1e9;
    for (int i = 0; i < n; ++i) {
        int root = find_set(i);
        if (is_sink[root]) {
            min_p = min(min_p, sz[root]);
        }
    }

    // Wypisywanie wyniku zgodnie ze specyfikacją wejścia/wyjścia (n zer/jedynek)
    for (int i = 0; i < n; ++i) {
        int root = find_set(i);
        if (is_sink[root] && sz[root] == min_p) {
            cout << 1 << (i == n - 1 ? "" : " ");
        } else {
            cout << 0 << (i == n - 1 ? "" : " ");
        }
    }
    cout << "\n";

    return 0;
}