// Slower C++ solution:
#include<iostream>

#include<algorithm>

#include<climits>

#include<vector>

#include<utility>

#include<cmath>

#include<string>

#include<cstring>

#include<map>

#include<queue>

#define rep(i,n) for(int i=0;i<n;i++)

#define rep1(i,n) for(int i=1;i<=n;i++)

#define prin(arg) std::cout<<arg<<"\n"

#define prin2(arg1,arg2) std::cout<<arg1<<" "<<arg2<<"\n"

#define fill(arg,n) std::memset(arg,n,sizeof(arg))

#define mp(a,b) std::make_pair(a,b)

using std::cin;

typedef long long ll;

typedef std::pair<int,int> pi;

typedef std::pair<int,ll> pil;

typedef std::vector<int> vi;

typedef std::vector<pil> vil;

const int INF=1e+9;

const ll INFLL=1e+17;

int N;

int u[100010],v[100010];

ll w[100010];

vil edge[100010];

ll d[100010];

bool F[100010];

void add_edge(int from,int to,ll cost){

  edge[from].push_back(mp(to,cost));

  edge[to].push_back(mp(from,cost));  

}

void bfs(){

  rep1(i,N) d[i]=INFLL;

  std::queue<pil> q;

  q.push(mp(u[0],0));

  d[u[0]]=0;

  while(!q.empty()){

    pil p=q.front();q.pop();

    int f=p.first;

    ll s=p.second;

    rep(i,edge[f].size()){

      pil pp=edge[f][i];

      int ff=pp.first;

      ll ss=pp.second;

      if(d[ff]==INFLL){

	d[ff]=s+ss;

	q.push(mp(ff,d[ff]));

      }

    }

  }

}

void solve(){

  rep(i,N-1) add_edge(u[i],v[i],w[i]);

  bfs();

  rep1(i,N){

    if(d[i]%2==0) prin(0);

    else prin(1);

  }

}

int main(){

  cin>>N;

  rep(i,N-1) cin>>u[i]>>v[i]>>w[i];

  solve();

  // rep1(i,N) prin2(i,d[i]);

  return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.4936709075493257x):
#include <iostream>

#include <algorithm>

#include <vector>

#include <queue>

#include <utility>

#define rep(i,n) for(int i=0;i<n;++i)

#define rep1(i,n) for(int i=1;i<=n;++i)

using namespace std;

typedef long long ll;

class Tree{

private:

  int n;//number of node

  int m;

  vector<vector<int>> edge;// edge does not have cost.

  vector<vector<pair<int,ll>>> edge2;// edge has cost.

  vector<ll> d;

public:  

  //*****Constructor************

  Tree(int n_){

    n = n_;

    edge.resize(n);

  }



  Tree(int n_,int m_,vector<int> a,vector<int> b){

    n = n_;

    m = m_;

    edge.resize(n);

    rep(i,m){

      edge[a[i]].push_back(b[i]);

      edge[b[i]].push_back(a[i]);

    }

  }



  Tree(int n_,int m_,vector<int> a,vector<int> b,vector<ll> c){

    n = n_;

    m = m_;

    edge2.resize(n);

    rep(i,m){

      edge2[a[i]].push_back({b[i],c[i]});

      edge2[b[i]].push_back({a[i],c[i]});

    }

  }  

  //*******************************************



  void bfs(){

    d.assign(n,-1);

    d[0] = 0;

    queue<int> q;

    q.push(0);

    while(!q.empty()){

      int v = q.front();q.pop();

      for(auto w:edge2[v]){

	if(d[w.first]>=0) continue;

	d[w.first] = d[v] + w.second;

	q.push(w.first);

      }

    }

    rep(i,n){

      if(d[i]%2==0) cout << 0 << "\n";

      else cout << 1 << "\n";

    }

  }

  

};







int main()

{

  int n;cin >> n;

  vector<int> a(n-1),b(n-1);

  vector<ll> c(n-1);

  rep(i,n-1){

    cin >> a[i] >> b[i] >> c[i];

    a[i]--;b[i]--;

  }

  Tree tr(n,n-1,a,b,c);

  tr.bfs();

  return 0;

}