#include <algorithm>  
#include <iostream>  
#include <sstream>  
#include <string>  
#include <cstring>
#include <vector>  
#include <queue>  
#include <set>  
#include <map>  
#include <cstdio>  
#include <cstdlib>  
#include <cctype>  
#include <cmath>  
#include <list>  
#include <cassert>
#include <ctime>
#include <climits>
using namespace std;  

#define PB push_back  
#define MP make_pair  
#define SZ(v) ((int)(v).size())  
#define FOR(i,a,b) for(int i=(a);i<(b);++i)  
#define REP(i,n) FOR(i,0,n)  
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)  
#define REPE(i,n) FORE(i,0,n)  
#define FORSZ(i,a,v) FOR(i,a,SZ(v))  
#define REPSZ(i,v) REP(i,SZ(v))  
typedef long long ll;
typedef unsigned long long ull;
ll gcd(ll a,ll b) { return b==0?a:gcd(b,a%b); }

const int MAXN=100000;
const int MAXBITS=4;
const int PMAXBITS=1<<MAXBITS;
void printmask(int mask) { printf("["); bool fst=true; FOR(j,1,1<<MAXBITS) if(mask&(1<<j)) { if(fst) fst=false; else printf(","); printf("%d",j); } printf("]"); }

int n;
vector<pair<int,int> > adj[MAXN];

pair<int,int> solve(int at,int par) {
	pair<int,int> ret=MP(0,0);
	REPSZ(i,adj[at]) {
		int to=adj[at][i].first; if(to==par) continue;
		pair<int,int> cur=solve(to,at);
		ret.first+=cur.first;
		int sum=adj[at][i].second;
		FOR(j,1,1<<MAXBITS) if(cur.second&(1<<j)) {
			sum^=j;
			if(ret.second&(1<<j)) ++ret.first;
			ret.second^=1<<j;
		}
		if(sum!=0) {
			if(ret.second&(1<<sum)) ++ret.first;
			ret.second^=1<<sum;
		}
	}
	//printf("%d: %d,",at,ret.first); printmask(ret.second); puts("");
	return ret;
}

int dp[1<<PMAXBITS];
int sum[1<<PMAXBITS];

int solve() {
	pair<int,int> res=solve(0,-1);
	int ans=res.first,mask=res.second;
	REP(i,1<<PMAXBITS) { sum[i]=0; REP(j,PMAXBITS) if(i&(1<<j)) sum[i]^=j; }
	dp[0]=0; FOR(i,1,1<<PMAXBITS) { dp[i]=sum[i]==0?1:0; int oth=(1<<PMAXBITS)-1-i; for(int j=(oth+1)&~oth;j<i;j=(j+oth+1)&~oth) if(sum[j]==0) dp[i]=max(dp[i],1+dp[i^j]); }
	REP(i,PMAXBITS) if(mask&(1<<i)) ++ans; ans-=dp[mask];
	return ans;
}

void run() {
	scanf("%d",&n); REP(i,n-1) { int a,b,c; scanf("%d%d%d",&a,&b,&c); adj[a].PB(MP(b,c)); adj[b].PB(MP(a,c)); }
	printf("%d\n",solve());
}

bool isleaf(int at,int par) {
	REPSZ(i,adj[at]) {
		int to=adj[at][i].first; if(to==par) continue;
		if(adj[at][i].second!=0||!isleaf(to,at)) return false;
	}
	return true;
}
bool dfspath(int at,int par,int end,int val,bool leafcheck) {
	int paridx=-1; REPSZ(i,adj[at]) if(adj[at][i].first==par) paridx=i;
	if(at==end) { if(paridx!=-1) adj[at][paridx].second^=val; return true; }
	REPSZ(i,adj[at]) {
		int to=adj[at][i].first; if(to==par) continue;
		if(leafcheck&&adj[at][i].second==0&&isleaf(to,at)||!dfspath(to,at,end,val,leafcheck)) continue;
		adj[at][i].second^=val; if(paridx!=-1) adj[at][paridx].second^=val;
		return true;
	}
	return false;
}
int bf(int dep=0) {
	int ret=INT_MAX; bool anypos=false;

	REP(at,n) {
		bool atisleaf=true; int npos=0;
		REPSZ(i,adj[at]) {
			int to=adj[at][i].first;
			if(adj[at][i].second>0) { ++npos; anypos=true; continue; }
			if(!isleaf(to,at)) atisleaf=false;
		}
		//if(!atisleaf||npos!=1) { REP(dd,dep) printf(" "); printf("%d is not a leaf\n",at); }
		if(!atisleaf||npos!=1) continue;
		//REP(dd,dep) printf(" "); printf("%d is leaf\n",at);
		REPSZ(i,adj[at]) {
			int to=adj[at][i].first; if(adj[at][i].second==0) continue;
			int val=adj[at][i].second;
			adj[at][i].second=0;
			REP(end,n) if(end!=at) {
				if(!dfspath(to,at,end,val,true)) continue;
				//REP(k,n) REPSZ(kk,adj[k]) printf("%d->%d = %d\n",k,adj[k][kk].first,adj[k][kk].second);
				//REP(dd,dep) printf(" "); printf("path of %d to %d\n",val,end);
				int cur=bf(dep+1); if(cur!=INT_MAX) ++cur;
				ret=min(ret,cur);
				dfspath(to,at,end,val,false);
			}
			adj[at][i].second=val;
		}
	}
	if(!anypos) return 0;
	return ret;
}

void stress() {
	REP(rep,1000) {
		n=6; REP(i,n) adj[i].clear(); REP(i,n-1) { int a=i+1,b=rand()%(i+1),c=rand()%8; adj[a].PB(MP(b,c)); adj[b].PB(MP(a,c)); }
		int have=solve();
		int want=bf();
		if(have==want) { printf("."); continue; }
		printf("%d\n",n); REP(at,n) REPSZ(i,adj[at]) { int to=adj[at][i].first; if(at<to) printf("%d %d %d\n",at,to,adj[at][i].second); }
		printf("have=%d want=%d\n",have,want);
	}
}

int main() {
	run();
	//stress();
	return 0;
}


Measured memory_bytes: 13696