// costel_brute_bfs.cpp
#include <bits/stdc++.h>

using namespace std;

class Color {
   public:
    Color(bool _value) : value(_value) {}

    static constexpr bool Red = false;
    static constexpr bool Blue = true;

    operator bool() const { return value; }
    operator bool &() { return value; }

   private:
    bool value;
};

struct Edge {
    int a, b;
    Color c;

    explicit Edge(int _a = -1, int _b = -1, Color _c = Color::Red)
        : a(_a), b(_b), c(_c) {}

    friend istream &operator>>(istream &i, Edge &e) {
        bool color;
        i >> e.a >> e.b >> color;
        --e.a, --e.b;
        e.c = (color == 0) ? Color::Red : Color::Blue;
        return i;
    }
};

struct Graph {
    int N;
    vector<Edge> edges;

    Graph() : N(-1) {}
    Graph(int _N) : N(_N) {}

    int M() const { return edges.size(); }

    friend istream &operator>>(istream &i, Graph &g) {
        int M;
        i >> g.N >> M;
        g.edges.resize(M);
        for (int j = 0; j < M; ++j) {
            i >> g.edges[j];
        }
        return i;
    }
};

bool bfs(int node, Color parity, const int init, const Color init_color,
         vector<vector<bool>> &vis, vector<vector<pair<int, Color>>> &graph,
         queue<pair<int, Color>> &q) {
    while (!q.empty()) {
        q.pop();
    }
    q.emplace(node, parity);
    vis[parity][node] = true;

    while (!q.empty()) {
        const auto &elem = q.front();
        node = elem.first;
        parity = elem.second;
        q.pop();

        for (const auto &it : graph[node]) {
            const int b = it.first;
            const Color c = it.second;
            if (c == parity) {
                if (b == init && parity != init_color) {
                    return true;
                }
                if (!vis[parity ^ 1][b]) {
                    vis[parity ^ 1][b] = true;
                    q.emplace(b, parity ^ 1);
                }
            }
        }
    }
    return false;
}

vector<bool> solve_brute(const Graph &g) {
    const int N = g.N;
    const int M = g.M();
    const vector<Edge> &edges = g.edges;

    vector<vector<pair<int, Color>>> graph(N);
    for (const Edge &edge : edges) {
        const int a = edge.a;
        const int b = edge.b;
        const Color c = edge.c;
        graph[a].emplace_back(b, c);
    }

    vector<vector<bool>> vis(2, vector<bool>(N, false));
    vector<bool> ans(N);
    // Allocate the queue a priori.
    queue<pair<int, Color>> q;
    for (int i = 0; i < N; ++i) {
        for (int i = 0; i < 2; ++i) {
            fill(vis[i].begin(), vis[i].end(), false);
        }
        ans[i] = bfs(i, Color::Red, i, Color::Red, vis, graph, q);
    }
    for (int i = 0; i < N; ++i) {
        if (!ans[i]) {
            for (int i = 0; i < 2; ++i) {
                fill(vis[i].begin(), vis[i].end(), false);
            }
            ans[i] = bfs(i, Color::Blue, i, Color::Blue, vis, graph, q);
        }
    }
    return ans;
}

void print_sol(ostream &o, const vector<bool> &sol) {
    for (int i = 0; i < static_cast<int>(sol.size()); ++i) {
        o << sol[i];
    }
    o << '\n';
}

int main() {
    Graph g;
    cin >> g;
    print_sol(cout, solve_brute(g));
    return 0;
}