#include<bits/stdc++.h>
typedef  long long int ll;
typedef  long double ld;
#define sync ios_base::sync_with_stdio(false); cin.tie(NULL) 
#define input(arr,n) for(ll i1=0;i1<n;i1++ )cin>>arr[i1]
#define mod 1000000007
#define F first
#define S second 
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#pragma GCC optimize("O3")
//recursions\
#pragma comment(linker, "/stack:200000000")
//loops\
#pragma GCC optimize("unroll-loops")
using namespace __gnu_pbds;
#define ordered_set tree<ll, null_type,less_equal<ll>, rb_tree_tag,tree_order_statistics_node_update>//s.order_of_key(val) *s.find_by_order(ind)
using namespace std;
int main()
{
	sync;
	ll n;
	cin>>n;
	vector<ll>v[n+1];	
	map<pair<ll,ll>,ll>mp;
	for(ll i=0;i<n-1;i++)
	{
		ll x,y;
		cin>>x>>y;
		v[x].push_back(y);
		v[y].push_back(x);
		mp[{x,y}]=i+1;
		mp[{y,x}]=i+1;
	}
	ll leaf=-1;
	for(ll i=1;i<=n;i++)
		if(v[i].size()==1)
			leaf=i;
			
	queue<ll>q;
	q.push(leaf);
	ll vis[n+1]={0},lev[n+1]={0};
	vis[leaf]=1;
	int flag=1,val=n-2;
	ll ans[n+1]={0};
	while(!q.empty())
	{
		ll top=q.front();
		q.pop();
		for(ll i=0;i<v[top].size();i++)
			if(!vis[v[top][i]])
			{
				vis[v[top][i]]=1;
				if(flag)
					ans[mp[{v[top][i],top}]]=0,flag=0;
				else
					ans[mp[{v[top][i],top}]]=val--;
				q.push(v[top][i]);
			}
	}
	for(ll i=1;i<=n-1;i++)
		cout<<ans[i]<<'\n';
}
	