#include <bits/stdc++.h>
using namespace std;
using ll=long long;
using vi=vector<int>;using vvi=vector<vi>;using vl=vector<ll>;
using P=pair<int,int>;using PL=pair<ll,ll>;using vp=vector<P>;
const int INF=1<<30,MOD=1000000007;const ll LINF=1ll<<60;
#define _ol3(_1,_2,_3,name,...) name
#define _rep(i,n) _repi(i,0,n)
#define _repi(i,a,b) for(int i=a,i##_l=(b);i<i##_l;++i)
#define REP(...) _ol3(__VA_ARGS__,_repi,_rep,)(__VA_ARGS__)
#define REPR(i,n) for(int i=n-1;i>=0;--i)
#define REPA(i,v) REP(i,v.size())
#define all(v) (v).begin(),(v).end()
#define bit(n) (1ll<<(n))
#define clamp(n,mi,ma) max(min(n,ma),mi)
#define uniq(v) sort(all(v));v.erase(unique(all(v)),v.end())
#define pb push_back
#define F first
#define S second
#define endl '\n'
#define cho(n,a,b) cout<<((n)?a:b)<<endl
#define YES(n) cho(n,"YES","NO")
#define Yes(n) cho(n,"Yes","No")
#define Poss(n) cho(n,"Possible","Impossible")
template<class T>bool chmax(T&a,const T&b){if(a<b){a=b;return 1;}return 0;}
template<class T>bool chmin(T&a,const T&b){if(a>b){a=b;return 1;}return 0;}
template<class T>ostream&operator<<(ostream&o,const vector<T>&v){for(auto&&i:v)o<<i<<' ';return o;}
template<class T>istream&operator>>(istream&i,vector<T>&v){for(T&j:v)i>>j;return i;}
template<class T,class U>ostream&operator<<(ostream&o,const pair<T,U>&p){return o<<p.F<<' '<<p.S;}
template<class T,class U>istream&operator>>(istream&i,pair<T,U>&p){return i>>p.F>>p.S;}
template<class T>ostream&operator<<(ostream&o,const set<T>&v){for(auto&&i:v)o<<i<<' ';return o;}
template<class T>ostream&operator<(ostream&o,const T&t){return o<<t;}
template<class T>istream&operator>(istream&i,T&t){return i>>t;}
#ifndef LOCAL
struct ostdmy{
template<class T>ostdmy&operator<<(const T&t){return*this;}
template<class T>ostdmy&operator<(const T&t){return*this;}};ostdmy cer_;
#define cerr cer_
#endif

class UnionFind{
private:
	vi data;
public:
	UnionFind(int size):data(size,-1){}
	bool unite(int x,int y){
		x=root(x);y=root(y);
		if(x!=y){
			if(data[y]<data[x])swap(x,y);
			data[x]+=data[y];data[y]=x;
		}
		return x!=y;
	}
	bool find(int x,int y){
		return root(x)==root(y);
	}
    inline bool isroot(int x){return data[x]<0;}
	int root(int x){
		return data[x]<0?x:data[x]=root(data[x]);
	}
	int size(int x){
		return -data[root(x)];
	}
};
#define MAX_V 100000
struct edge {int to,cost;};
int V,E;
vector<edge> G[MAX_V];
int d[MAX_V];
void dijkstra(int start){
    priority_queue<P,vector<P>,greater<P>> Q;
    fill(d,d+V,INF);
    d[start]=0;
    Q.push(make_pair(0,start));
    while(!Q.empty()){
        P p=Q.top();
        Q.pop();
        int v=p.second;
        if(d[v]<p.first)continue;
        REPA(i,G[v]){
            edge e=G[v][i];
            if(d[e.to]>d[v]+e.cost){
                d[e.to]=d[v]+e.cost;
                Q.push(make_pair(d[e.to],e.to));
            }
        }
    }
}
int main(){
    cin.tie(0);ios::sync_with_stdio(0);
    int n;
    cin>n;
    UnionFind uf(n);
    vector<P> ncs;//no connection

    REP(i,n-1){
        int u,v,w;
        cin>u>v>w;
        --u;--v;
        if(w%2==0){
            uf.unite(u,v);
        }else{
            ncs.pb({u,v});
        }
    }
    for(auto& p:ncs){
        p.F=uf.root(p.F);
        p.S=uf.root(p.S);
    }
    int root=-1;
    REP(i,n){
        if(uf.isroot(i)){
        root=i;break;}
    }
    V=n;
    E=ncs.size();
    for(auto& p:ncs){
        G[p.F].push_back({p.S,1});
        G[p.S].push_back({p.F,1});
    }
    dijkstra(root);
    REP(i,n){
        cout<<d[uf.root(i)]%2<<endl;
    }
    return 0;
}


Measured memory_bytes: 7796