#include <bits/stdc++.h>
using namespace std;
#define sqr(x) ((x)*(x))
#define sz(v) int(v.size())
#define par make_pair
#define pb push_back
#define fi first
#define se second
#define endl '\n'
template<class X, class Y> void amax(X& x, const Y& y){if(x < y) x = y;}
template<class X, class Y> void amin(X& x, const Y& y){if(x > y) x = y;}
typedef vector<int> vi; typedef pair<int, int> ii; typedef long long ll; typedef long double ld;
const int INF = 1e9 + 10; const ll INFL = 1e18 + 10;
const int MAX = 110;
struct edge{
    int u, v, f, c;
};

struct mincost{
    int n, s, t;
    vector<edge> ed;
    vector<vi> es;
    vector<bool> mark;
    vi trace, dd;

    mincost(int n, int s, int t): n(n), s(s), t(t){
        es.resize(n);
        trace.resize(n);
        mark.resize(n);
        dd.resize(n);
    }

    void add(int u, int v, int f, int c){
        edge e;
        e.u = u;
        e.v = v;
        e.f = f;
        e.c = c;
        ed.pb(e);
        es[e.u].pb(sz(ed) - 1);
        swap(e.u, e.v);
        e.f = 0;
        e.c = -e.c;
        ed.pb(e);
        es[e.u].pb(sz(ed) - 1);
    }

    bool spfa(){
        fill(dd.begin(), dd.end(), INF);
        fill(trace.begin(), trace.end(), -1);
        fill(mark.begin(), mark.end(), false);
        queue<int> qe;
        qe.push(s);
        dd[s] = 0; mark[s] = true;
        while(!qe.empty()){
            int u = qe.front(); qe.pop();
            for(auto e : es[u])
            if(ed[e].f && dd[ed[e].v] > dd[u] + ed[e].c){
                dd[ed[e].v] = dd[u] + ed[e].c;
                trace[ed[e].v] = e;
                if(!mark[ed[e].v]){
                    mark[ed[e].v] = true;
                    qe.push(ed[e].v);
                }
            }
        }
        return dd[t] != INF;
    }

    int flow(){
        ll res = 0;
        while(spfa()){
            int x = t, inc = INF;
            while(trace[x] != -1){
                amin(inc, ed[trace[x]].f);
                x = ed[trace[x]].u;
            }
            x = t;
            while(trace[x] != -1){
                ed[trace[x]].f -= inc;
                ed[trace[x] ^ 1].f += inc;
                x = ed[trace[x]].u;
            }
            res += dd[t]*inc;
        }
        return res;
    }
};

int n, m;
int b[MAX];
int res;

void process(){
    cin >> n >> m;
    mincost mc(n + 2, 0, n + 1);
    for(int i = 1; i <= m; i++){
        int u, v, c, f;
        cin >> u >> v >> c >> f;
        b[u] += f;
        b[v] -= f;
        mc.add(u, v, INF, 2);
        if(c < f){
            res += f - c;
            mc.add(v, u, f - c, 0);
            mc.add(v, u, c, 1);
        }else{
            mc.add(u, v, c - f, 1);
            mc.add(v, u, f, 1);
        }
    }

    for(int i = 1; i <= n; i++){
        if(b[i] < 0){
            mc.add(0, i, -b[i], 0);
        }else if(b[i] > 0){
            mc.add(i, n + 1, b[i], 0);
        }
    }
    mc.add(n, 1, INF, 0);
    cout << res + mc.flow();
}

int main(){
    ios_base::sync_with_stdio(false);
    //~ cin.tie(nullptr);
    //~ freopen("d.in", "r", stdin);
    process();
}


#include <bits/stdc++.h>
using namespace std;
vector<int> v[100005];
int ans[100005];
int main(){
	int n;
	scanf("%d",&n);
	for (int i=1;i<n;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		v[a].push_back(i);
		v[b].push_back(i);
		ans[i]=-1;
	}
	pair<int,int> mx(0,0);
	for (int i=1;i<=n;i++)
	mx=max(mx,make_pair((int)v[i].size(),i));
	int cur=0;
	for (int i:v[mx.second])
	ans[i]=cur++;
	for (int i=1;i<n;i++)
	{
		if (ans[i]==-1)
		ans[i]=cur++;
		printf("%d\n",ans[i]);
	}
}


#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int t,n,a[MAX],b[MAX],book[MAX],c[MAX];
int main(){
    memset(c,-1,sizeof(c));
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    int temp=0;
    for(int i=1;i<n;i++){
        if(c[i]==-1){
            if(book[a[i]]+book[b[i]]==0){
                c[i]=temp;
                book[a[i]]=1;
                book[b[i]]=1;
                temp++;
            }
        }
    }
    for(int i=n-1;i>=1;i--){
        if(c[i]==-1){
            if(book[a[i]]+book[b[i]]==1){
                c[i]=temp;
                book[a[i]]=1;
                book[b[i]]=1;
                temp++;
            }
        }
    }
    for(int i=1;i<n;i++){
        if(c[i]==-1){
            if(book[a[i]]+book[b[i]]==2){
                c[i]=temp;
                book[a[i]]=1;
                book[b[i]]=1;
                temp++;
            }
        }
    }
    for(int i=1;i<n;i++){
        printf("%d\n",c[i]);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int t,n,a[MAX],b[MAX],book[MAX],c[MAX];
int main(){
    memset(c,-1,sizeof(c));
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    int temp=0;
    for(int k=0;k<=2;k++){
        for(int i=1;i<n;i++){
            if(c[i]==-1){
                if(book[a[i]]+book[a[i]]==k){
                    c[i]=temp;
                    book[a[i]]=1;
                    book[b[i]]=1;
                    temp++;
                }
            }
        }
    }
    for(int i=1;i<n;i++){
        printf("%d\n",c[i]);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
struct AK{
    int x;
    int y;
}a[MAX];
bool cmp(AK A,AK B){
    if(A.x==B.x)return A.y<B.y;
    else return A.x<B.x;
}
int t,n,book[MAX],c[MAX];
int main(){
    memset(c,-1,sizeof(c));
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&a[i].x,&a[i].y);
    }
    sort(a+1,a+n,cmp);
    int temp=0;
    for(int i=1;i<n;i++){
        if(c[i]==-1){
            if(book[a[i].x]+book[a[i].y]==0){
                c[i]=temp;
                book[a[i].x]=1;
                book[a[i].y]=1;
                temp++;
            }
        }
    }
    for(int i=n-1;i>=1;i--){
        if(c[i]==-1){
            if(book[a[i].x]+book[a[i].y]==1){
                c[i]=temp;
                book[a[i].x]=1;
                book[a[i].y]=1;
                temp++;
            }
        }
    }
    for(int i=1;i<n;i++){
        if(c[i]==-1){
            if(book[a[i].x]+book[a[i].y]==2){
                c[i]=temp;
                book[a[i].x]=1;
                book[a[i].y]=1;
                temp++;
            }
        }
    }
    for(int i=1;i<n;i++){
        printf("%d\n",c[i]);
    }
    return 0;
}


#include<bits/stdc++.h>
using namespace std;
const int MAX=1e5+5;
int t,n,a[MAX],b[MAX],book[MAX],c[MAX];
int main(){
    memset(c,-1,sizeof(c));
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        scanf("%d%d",&a[i],&b[i]);
    }
    int temp=0;
    for(int k=0;k<=2;k++){
        for(int i=1;i<n;i++){
            if(c[i]==-1){
                if(book[a[i]]+book[b[i]]==k){
                    c[i]=temp;
                    book[a[i]]=1;
                    book[b[i]]=1;
                    temp++;
                }
            }
        }
    }
    for(int i=1;i<n;i++){
        printf("%d\n",c[i]);
    }
    return 0;
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
	ll p = 0;
	ll count = 2;
	ll n;
	cin >> n;
	map<pair<ll,ll> ,ll > m;
	vector<ll> v[n+1];
	vector<pair<ll,ll>> v2;
	for(int i = 1 ; i < n +1; i ++)
	{
		v[i].push_back(-1);
	}
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		v[a].push_back(b);
		v2.push_back(make_pair(a,b));
		m[{a,b}] = -1;
	}
	for(int i = 1 ; i < n + 1; i ++)
	{
		for(int j = 1 ; j < v[i].size() ; j++)
		{
			if(v[v[i][j]].size() == 1) {
				if(p != 2) {
					m[{i,v[i][j]}] = p;
					p++;
				}
				else
					m[{i,v[i][j]}] = count++;
			}
			else
				m[{i,v[i][j]}] = count++;

			//cout << v[i][j] << " ";
		}
		//cout << "\n";
	}
	for(int i = 0 ; i < n - 1 ; i ++)
	{
		cout << m[{v2[i].first,v2[i].second}] << "\n";
	}
}


//ye code shayad chal jaaye because it was written by gawwwd adarshpagarwal
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < n-1 ; j ++)
			{
				pair<ll,ll> p= v[j];
				if((p.first == i || p.second == i) && edges[p] == -1)
					edges[p] = count++;
			}
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
//noooooooooooooooooooooooooob
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll> adj[100005],vec;
bool vis[100005];
void bfs(ll u)
{
	queue<ll> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
			ll f = q.front();
			q.pop();
			cout << f << " ";
			for (auto i = adj[f].begin(); i != adj[f].end(); i++) {
					if (!vis[*i]) {
							q.push(*i);
							vis[*i] = true;
					}
			}
	}
}
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
		if(adj[b].size() > max)
			max = adj[b].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < n-1 ; j ++)
			{
				pair<ll,ll> p= v[j];
				if((p.first == i || p.second == i) && edges[p] == -1)
					edges[p] = count++;
			}
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
//noooooooooooooooooooooooooob
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll> adj[100005],vec;
bool vis[100005];
void bfs(ll u)
{
	queue<ll> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
			ll f = q.front();
			q.pop();
			cout << f << " ";
			for (auto i = adj[f].begin(); i != adj[f].end(); i++) {
					if (!vis[*i]) {
							q.push(*i);
							vis[*i] = true;
					}
			}
	}
}
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
		if(adj[b].size() > max)
			max = adj[a].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < n-1 ; j ++)
			{
				pair<ll,ll> p= v[j];
				if((p.first == i || p.second == i) && edges[p] == -1)
					edges[p] = count++;
			}
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
//noooooooooooooooooooooooooob
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll> adj[100005],vec;
bool vis[100005];
void bfs(ll u)
{
	queue<ll> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
			ll f = q.front();
			q.pop();
			cout << f << " ";
			for (auto i = adj[f].begin(); i != adj[f].end(); i++) {
					if (!vis[*i]) {
							q.push(*i);
							vis[*i] = true;
					}
			}
	}
}
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
		if(adj[b].size() > max)
			max = adj[b].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < adj[i].size() ; j++)
			{
				pair<ll,ll> p1= make_pair(i,adj[i][j]);
				pair<ll,ll> p2= make_pair(adj[i][j],i);
				if(edges.find(p1) != edges.end())
					edges[p1] = count++;
				else
					edges[p2] = count++;
			}
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
//noooooooooooooooooooooooooob
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll> adj[100005],vec;
bool vis[100005];
void bfs(ll u)
{
	queue<ll> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
			ll f = q.front();
			q.pop();
			cout << f << " ";
			for (auto i = adj[f].begin(); i != adj[f].end(); i++) {
					if (!vis[*i]) {
							q.push(*i);
							vis[*i] = true;
					}
			}
	}
}
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < n-1 ; j ++)
			{
				pair<ll,ll> p= v[j];
				if((p.first == i || p.second == i) && edges[p] == -1)
					edges[p] = count++;
			}
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


/*Is code me pakka TLE aayega,ya to WA,ya fir hack ho jayega
ya system testing me fail kar jayega,ya fir runtime error
ya MLE*/
//noooooooooooooooooooooooooob
#include<bits/stdc++.h>
using namespace std;
#define ll long long
vector<ll> adj[100005],vec;
bool vis[100005];
void bfs(ll u)
{
	queue<ll> q;
	q.push(u);
	vis[u] = true;
	while (!q.empty()) {
			ll f = q.front();
			q.pop();
			cout << f << " ";
			for (auto i = adj[f].begin(); i != adj[f].end(); i++) {
					if (!vis[*i]) {
							q.push(*i);
							vis[*i] = true;
					}
			}
	}
}
int main()
{
	ll n;
	cin >> n;
	map<pair<ll,ll>,ll> edges;
	vector<pair<ll,ll>> v;
	ll max = 0;
	for(int i = 0 ; i < n-1 ; i ++)
	{
		ll a,b;
		cin >> a >> b;
		adj[a].push_back(b);
		adj[b].push_back(a);
		v.push_back({a,b});
		edges[{a,b}] = -1;
		if(adj[a].size() > max)
			max = adj[a].size();
		if(adj[b].size() > max)
			max = adj[b].size();
	}
	ll count = 0;
	for(int i = 1 ; i <= n ; i ++)
	{
		if(adj[i].size() == max)
		{
			for(int j = 0 ; j < adj[i].size() ; j++)
			{
				pair<ll,ll> p1= make_pair(i,adj[i][j]);
				pair<ll,ll> p2= make_pair(adj[i][j],i);
				if(edges.find(p1) != edges.end())
					edges[p1] = count++;
				else
					edges[p2] = count++;
			}
			break;
		}
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		pair<ll,ll> p= v[j];
		if(edges[p] == -1)
			edges[p] = count++;
	}
	for(int j = 0 ; j < n-1 ; j ++)
	{
		cout << edges[v[j]] << "\n";
	}
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[200000];
void solve()
{
	int n;
	cin>>n;
	int dpp[n+1];
	vector<int> adj[n+2];
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define mxmn 100010
vector <int> vd[mxmn];
struct AdjListNode
{
	int dest;
	int weight;
	struct AdjListNode* next;
};

// A structure to represent an adjacency list
struct AdjList
{
	struct AdjListNode *head; // pointer to head node of list
};

// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
	int V;
	struct AdjList* array;
};

// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest, int weight)
{
	struct AdjListNode* newNode =
			(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
	newNode->dest = dest;
	newNode->weight = weight;
	newNode->next = NULL;
	return newNode;
}

// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
	struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
	graph->V = V;

	// Create an array of adjacency lists. Size of array will be V
	graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));

	// Initialize each adjacency list as empty by making head as NULL
	for (int i = 0; i < V; ++i)
		graph->array[i].head = NULL;

	return graph;
}

// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest, int weight)
{
	// Add an edge from src to dest. A new node is added to the adjacency
	// list of src. The node is added at the beginning
	struct AdjListNode* newNode = newAdjListNode(dest, weight);
	newNode->next = graph->array[src].head;
	graph->array[src].head = newNode;

	// Since graph is undirected, add an edge from dest to src also
	newNode = newAdjListNode(src, weight);
	newNode->next = graph->array[dest].head;
	graph->array[dest].head = newNode;
}

// Structure to represent a min heap node
struct MinHeapNode
{
	int v;
	int dist;
};

// Structure to represent a min heap
struct MinHeap
{
	int size;	 // Number of heap nodes present currently
	int capacity; // Capacity of min heap
	int *pos;	 // This is needed for decreaseKey()
	struct MinHeapNode **array;
};

// A utility function to create a new Min Heap Node
struct MinHeapNode* newMinHeapNode(int v, int dist)
{
	struct MinHeapNode* minHeapNode =
		(struct MinHeapNode*) malloc(sizeof(struct MinHeapNode));
	minHeapNode->v = v;
	minHeapNode->dist = dist;
	return minHeapNode;
}

// A utility function to create a Min Heap
struct MinHeap* createMinHeap(int capacity)
{
	struct MinHeap* minHeap =
		(struct MinHeap*) malloc(sizeof(struct MinHeap));
	minHeap->pos = (int *)malloc(capacity * sizeof(int));
	minHeap->size = 0;
	minHeap->capacity = capacity;
	minHeap->array =
		(struct MinHeapNode**) malloc(capacity * sizeof(struct MinHeapNode*));
	return minHeap;
}

// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
	struct MinHeapNode* t = *a;
	*a = *b;
	*b = t;
}

// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
	int smallest, left, right;
	smallest = idx;
	left = 2 * idx + 1;
	right = 2 * idx + 2;

	if (left < minHeap->size &&
		minHeap->array[left]->dist < minHeap->array[smallest]->dist )
	smallest = left;

	if (right < minHeap->size &&
		minHeap->array[right]->dist < minHeap->array[smallest]->dist )
	smallest = right;

	if (smallest != idx)
	{
		// The nodes to be swapped in min heap
		MinHeapNode *smallestNode = minHeap->array[smallest];
		MinHeapNode *idxNode = minHeap->array[idx];

		// Swap positions
		minHeap->pos[smallestNode->v] = idx;
		minHeap->pos[idxNode->v] = smallest;

		// Swap nodes
		swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);

		minHeapify(minHeap, smallest);
	}
}

// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
	return minHeap->size == 0;
}

// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
	if (isEmpty(minHeap))
		return NULL;

	// Store the root node
	struct MinHeapNode* root = minHeap->array[0];

	// Replace root node with last node
	struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
	minHeap->array[0] = lastNode;

	// Update position of last node
	minHeap->pos[root->v] = minHeap->size-1;
	minHeap->pos[lastNode->v] = 0;

	// Reduce heap size and heapify root
	--minHeap->size;
	minHeapify(minHeap, 0);

	return root;
}

// Function to decreasy dist value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int dist)
{
	// Get the index of v in heap array
	int i = minHeap->pos[v];

	// Get the node and update its dist value
	minHeap->array[i]->dist = dist;

	// Travel up while the complete tree is not hepified.
	// This is a O(Logn) loop
	while (i && minHeap->array[i]->dist < minHeap->array[(i - 1) / 2]->dist)
	{
		// Swap this node with its parent
		minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
		minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
		swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);

		// move to parent index
		i = (i - 1) / 2;
	}
}

// A utility function to check if a given vertex
// 'v' is in min heap or not
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
	return true;
return false;
}

// A utility function used to print the solution

// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
void printArr(int dist[], int n)
{
	vector<pair<int,int> > pt;
	for (int i = 0; i < n; ++i)
		pt.push_back(make_pair(dist[i],i));
	sort(pt.begin(),pt.end());
	int wt = n-2;
	int dp[n+1];
	for(int i=1;i<n;i++)
	{
		dp[pt[i].second] = wt--;
	}
	for(int i=n-1;i>0;i--)
	{
		cout<<dp[i]<<"\n";
	}
}
void dijkstra(struct Graph* graph, int src)
{
	int V = graph->V;// Get the number of vertices in graph
	int dist[V];	 // dist values used to pick minimum weight edge in cut

	// minHeap represents set E
	struct MinHeap* minHeap = createMinHeap(V);

	// Initialize min heap with all vertices. dist value of all vertices
	for (int v = 0; v < V; ++v)
	{
		dist[v] = INT_MAX;
		minHeap->array[v] = newMinHeapNode(v, dist[v]);
		minHeap->pos[v] = v;
	}

	// Make dist value of src vertex as 0 so that it is extracted first
	minHeap->array[src] = newMinHeapNode(src, dist[src]);
	minHeap->pos[src] = src;
	dist[src] = 0;
	decreaseKey(minHeap, src, dist[src]);

	// Initially size of min heap is equal to V
	minHeap->size = V;

	// In the followin loop, min heap contains all nodes
	// whose shortest distance is not yet finalized.
	while (!isEmpty(minHeap))
	{
		// Extract the vertex with minimum distance value
		struct MinHeapNode* minHeapNode = extractMin(minHeap);
		int u = minHeapNode->v; // Store the extracted vertex number

		// Traverse through all adjacent vertices of u (the extracted
		// vertex) and update their distance values
		struct AdjListNode* pCrawl = graph->array[u].head;
		while (pCrawl != NULL)
		{
			int v = pCrawl->dest;

			// If shortest distance to v is not finalized yet, and distance to v
			// through u is less than its previously calculated distance
			if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
										pCrawl->weight + dist[u] < dist[v])
			{
				dist[v] = dist[u] + pCrawl->weight;

				// update distance value in min heap also
				decreaseKey(minHeap, v, dist[v]);
			}
			pCrawl = pCrawl->next;
		}
	}
	 printArr(dist,V);
}
void solve()
{
	int n;
	cin>>n;
	int u,v;
	struct Graph* graph = createGraph(n);
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		addEdge(graph, --u, --v, 1);
		vd[u].push_back(v);
		vd[v].push_back(u);
	}
	dijkstra(graph, 0);
}
signed main()
{
	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
//	cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 100008;
int dpp[100005];
vector<int> adj[100005];
void solve()
{
	int n;
	cin>>n;
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u;
		cin>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j++;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	while(t--)
	{
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
void solve()
{
	int n;
	cin>>n;
	int dpp[n+1];
	vector<int> adj[n+2];
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 100008;
int dpp[100005];
vector<int> adj[100005];
void solve()
{
	int n;
	cin>>n;
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u;
		cin>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	while(t--)
	{
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 1e5;
int dpp[mxN+10];
std::vector<int> adj[mxN+10];
void solve()
{
	int n;
	cin>>n;
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define mxmn 100010
vector <int> vd[mxmn];
struct AdjListNode
{
	int dest;
	int weight;
	struct AdjListNode* next;
};

// A structure to represent an adjacency list
struct AdjList
{
	struct AdjListNode *head; // pointer to head node of list
};

// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
	int V;
	struct AdjList* array;
};

// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest, int weight)
{
	struct AdjListNode* newNode =
			(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
	newNode->dest = dest;
	newNode->weight = weight;
	newNode->next = NULL;
	return newNode;
}

// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
	struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
	graph->V = V;

	// Create an array of adjacency lists. Size of array will be V
	graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));

	// Initialize each adjacency list as empty by making head as NULL
	for (int i = 0; i < V; ++i)
		graph->array[i].head = NULL;

	return graph;
}

// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest, int weight)
{
	// Add an edge from src to dest. A new node is added to the adjacency
	// list of src. The node is added at the beginning
	struct AdjListNode* newNode = newAdjListNode(dest, weight);
	newNode->next = graph->array[src].head;
	graph->array[src].head = newNode;

	// Since graph is undirected, add an edge from dest to src also
	newNode = newAdjListNode(src, weight);
	newNode->next = graph->array[dest].head;
	graph->array[dest].head = newNode;
}

// Structure to represent a min heap node
struct MinHeapNode
{
	int v;
	int dist;
};

// Structure to represent a min heap
struct MinHeap
{
	int size;	 // Number of heap nodes present currently
	int capacity; // Capacity of min heap
	int *pos;	 // This is needed for decreaseKey()
	struct MinHeapNode **array;
};

// A utility function to create a new Min Heap Node
struct MinHeapNode* newMinHeapNode(int v, int dist)
{
	struct MinHeapNode* minHeapNode =
		(struct MinHeapNode*) malloc(sizeof(struct MinHeapNode));
	minHeapNode->v = v;
	minHeapNode->dist = dist;
	return minHeapNode;
}

// A utility function to create a Min Heap
struct MinHeap* createMinHeap(int capacity)
{
	struct MinHeap* minHeap =
		(struct MinHeap*) malloc(sizeof(struct MinHeap));
	minHeap->pos = (int *)malloc(capacity * sizeof(int));
	minHeap->size = 0;
	minHeap->capacity = capacity;
	minHeap->array =
		(struct MinHeapNode**) malloc(capacity * sizeof(struct MinHeapNode*));
	return minHeap;
}

// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
	struct MinHeapNode* t = *a;
	*a = *b;
	*b = t;
}

// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
	int smallest, left, right;
	smallest = idx;
	left = 2 * idx + 1;
	right = 2 * idx + 2;

	if (left < minHeap->size &&
		minHeap->array[left]->dist < minHeap->array[smallest]->dist )
	smallest = left;

	if (right < minHeap->size &&
		minHeap->array[right]->dist < minHeap->array[smallest]->dist )
	smallest = right;

	if (smallest != idx)
	{
		// The nodes to be swapped in min heap
		MinHeapNode *smallestNode = minHeap->array[smallest];
		MinHeapNode *idxNode = minHeap->array[idx];

		// Swap positions
		minHeap->pos[smallestNode->v] = idx;
		minHeap->pos[idxNode->v] = smallest;

		// Swap nodes
		swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);

		minHeapify(minHeap, smallest);
	}
}

// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
	return minHeap->size == 0;
}

// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
	if (isEmpty(minHeap))
		return NULL;

	// Store the root node
	struct MinHeapNode* root = minHeap->array[0];

	// Replace root node with last node
	struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
	minHeap->array[0] = lastNode;

	// Update position of last node
	minHeap->pos[root->v] = minHeap->size-1;
	minHeap->pos[lastNode->v] = 0;

	// Reduce heap size and heapify root
	--minHeap->size;
	minHeapify(minHeap, 0);

	return root;
}

// Function to decreasy dist value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int dist)
{
	// Get the index of v in heap array
	int i = minHeap->pos[v];

	// Get the node and update its dist value
	minHeap->array[i]->dist = dist;

	// Travel up while the complete tree is not hepified.
	// This is a O(Logn) loop
	while (i && minHeap->array[i]->dist < minHeap->array[(i - 1) / 2]->dist)
	{
		// Swap this node with its parent
		minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
		minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
		swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);

		// move to parent index
		i = (i - 1) / 2;
	}
}

// A utility function to check if a given vertex
// 'v' is in min heap or not
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
	return true;
return false;
}
int loca[mxmn];
// A utility function used to print the solution

// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
int dp[200000];
void printArr(int dist[], int n)
{
	vector<pair<int,int> > pt;
	for (int i = 0; i < n; ++i)
		pt.push_back(make_pair(dist[i],i));
	sort(pt.begin(),pt.end());
//	for(int i=0;i<n;i++)
//	{
//		cout<<pt[i].first<<" "<<pt[i].second<<"\n";
//	}
	int wt = n-2;
	memset(dp,-1,2*n+2);
	for(int i=1;i<n;i++)
	{
	//	if(i%2!=0)
	//	{
			dp[loca[pt[i].second]] = wt--;
	//	}
	//	else
	//	{
	//		dp[loca[pt[i].second]] = wt--;
	//	}
	}
	for(int i=0;i<n-1;i++)
	{
		if(dp[i]!=-1)
		cout<<dp[i]<<"\n";
	}
}
void dijkstra(struct Graph* graph, int src)
{
	int V = graph->V;// Get the number of vertices in graph
	int dist[V];	 // dist values used to pick minimum weight edge in cut

	// minHeap represents set E
	struct MinHeap* minHeap = createMinHeap(V);

	// Initialize min heap with all vertices. dist value of all vertices
	for (int v = 0; v < V; ++v)
	{
		dist[v] = INT_MAX;
		minHeap->array[v] = newMinHeapNode(v, dist[v]);
		minHeap->pos[v] = v;
	}

	// Make dist value of src vertex as 0 so that it is extracted first
	minHeap->array[src] = newMinHeapNode(src, dist[src]);
	minHeap->pos[src] = src;
	dist[src] = 0;
	decreaseKey(minHeap, src, dist[src]);

	// Initially size of min heap is equal to V
	minHeap->size = V;

	// In the followin loop, min heap contains all nodes
	// whose shortest distance is not yet finalized.
	while (!isEmpty(minHeap))
	{
		// Extract the vertex with minimum distance value
		struct MinHeapNode* minHeapNode = extractMin(minHeap);
		int u = minHeapNode->v; // Store the extracted vertex number

		// Traverse through all adjacent vertices of u (the extracted
		// vertex) and update their distance values
		struct AdjListNode* pCrawl = graph->array[u].head;
		while (pCrawl != NULL)
		{
			int v = pCrawl->dest;

			// If shortest distance to v is not finalized yet, and distance to v
			// through u is less than its previously calculated distance
			if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
										pCrawl->weight + dist[u] < dist[v])
			{
				dist[v] = dist[u] + pCrawl->weight;

				// update distance value in min heap also
				decreaseKey(minHeap, v, dist[v]);
			}
			pCrawl = pCrawl->next;
		}
	}
	 printArr(dist,V);
}
void solve()
{
	int n;
	cin>>n;
	int u,v;
	struct Graph* graph = createGraph(n);
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		loca[v-1] = i+1;
		addEdge(graph, u-1, v-1, 1);
		vd[--u].push_back(--v);
	}
	int vaj = 0;
	int dpp[n+1];
	int cnt = 0;
	for(int i=0;i<n;i++)
	{
		if(vd[i].size()==0 && loca[i]!=0)
		{
			cnt++;
			dpp[loca[i]-1] = vaj++;
		}
	}
	vaj = cnt;
	for(int i=0;i<n;i++)
	{
		if(vd[i].size()!=0 && loca[i]!=0)
		{
			dpp[loca[i]-1] = vaj++;
		}
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<dpp[i]<<"\n";
	}
	//dijkstra(graph, 0);
}
signed main()
{
	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
//	cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
	//	adj[u].push_back(i);
	//	adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j++;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
// 	#ifndef LINE_JUDGE
  //  // for getting input from input.txt
   // /freopen("input.txt", "r", stdin);
   // // for writing output to output.txt
  //  freopen("output.txt", "w", stdout);
   // #endif
	//int t = 1;
///	while(t--)
//	{
		solve();
	//}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	memset(dpp,-1,100005);
	scanf("%d",&n);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	solve();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
void solve()
{
	int n;
	cin>>n;
	int dpp[n+1];
	vector<int> adj[n+2];
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
// 	#ifndef LINE_JUDGE
  //  // for getting input from input.txt
   // /freopen("input.txt", "r", stdin);
   // // for writing output to output.txt
  //  freopen("output.txt", "w", stdout);
   // #endif
	//int t = 1;
///	while(t--)
//	{
		solve();
	//}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
// 	#ifndef LINE_JUDGE
  //  // for getting input from input.txt
   // /freopen("input.txt", "r", stdin);
   // // for writing output to output.txt
  //  freopen("output.txt", "w", stdout);
   // #endif
	//int t = 1;
///	while(t--)
//	{
		solve();
	//}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define mxmn 100010
vector <int> vd[mxmn];
struct AdjListNode
{
	int dest;
	int weight;
	struct AdjListNode* next;
};

// A structure to represent an adjacency list
struct AdjList
{
	struct AdjListNode *head; // pointer to head node of list
};

// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
	int V;
	struct AdjList* array;
};

// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest, int weight)
{
	struct AdjListNode* newNode =
			(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
	newNode->dest = dest;
	newNode->weight = weight;
	newNode->next = NULL;
	return newNode;
}

// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
	struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
	graph->V = V;

	// Create an array of adjacency lists. Size of array will be V
	graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));

	// Initialize each adjacency list as empty by making head as NULL
	for (int i = 0; i < V; ++i)
		graph->array[i].head = NULL;

	return graph;
}

// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest, int weight)
{
	// Add an edge from src to dest. A new node is added to the adjacency
	// list of src. The node is added at the beginning
	struct AdjListNode* newNode = newAdjListNode(dest, weight);
	newNode->next = graph->array[src].head;
	graph->array[src].head = newNode;

	// Since graph is undirected, add an edge from dest to src also
	newNode = newAdjListNode(src, weight);
	newNode->next = graph->array[dest].head;
	graph->array[dest].head = newNode;
}

// Structure to represent a min heap node
struct MinHeapNode
{
	int v;
	int dist;
};

// Structure to represent a min heap
struct MinHeap
{
	int size;	 // Number of heap nodes present currently
	int capacity; // Capacity of min heap
	int *pos;	 // This is needed for decreaseKey()
	struct MinHeapNode **array;
};

// A utility function to create a new Min Heap Node
struct MinHeapNode* newMinHeapNode(int v, int dist)
{
	struct MinHeapNode* minHeapNode =
		(struct MinHeapNode*) malloc(sizeof(struct MinHeapNode));
	minHeapNode->v = v;
	minHeapNode->dist = dist;
	return minHeapNode;
}

// A utility function to create a Min Heap
struct MinHeap* createMinHeap(int capacity)
{
	struct MinHeap* minHeap =
		(struct MinHeap*) malloc(sizeof(struct MinHeap));
	minHeap->pos = (int *)malloc(capacity * sizeof(int));
	minHeap->size = 0;
	minHeap->capacity = capacity;
	minHeap->array =
		(struct MinHeapNode**) malloc(capacity * sizeof(struct MinHeapNode*));
	return minHeap;
}

// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
	struct MinHeapNode* t = *a;
	*a = *b;
	*b = t;
}

// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
	int smallest, left, right;
	smallest = idx;
	left = 2 * idx + 1;
	right = 2 * idx + 2;

	if (left < minHeap->size &&
		minHeap->array[left]->dist < minHeap->array[smallest]->dist )
	smallest = left;

	if (right < minHeap->size &&
		minHeap->array[right]->dist < minHeap->array[smallest]->dist )
	smallest = right;

	if (smallest != idx)
	{
		// The nodes to be swapped in min heap
		MinHeapNode *smallestNode = minHeap->array[smallest];
		MinHeapNode *idxNode = minHeap->array[idx];

		// Swap positions
		minHeap->pos[smallestNode->v] = idx;
		minHeap->pos[idxNode->v] = smallest;

		// Swap nodes
		swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);

		minHeapify(minHeap, smallest);
	}
}

// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
	return minHeap->size == 0;
}

// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
	if (isEmpty(minHeap))
		return NULL;

	// Store the root node
	struct MinHeapNode* root = minHeap->array[0];

	// Replace root node with last node
	struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
	minHeap->array[0] = lastNode;

	// Update position of last node
	minHeap->pos[root->v] = minHeap->size-1;
	minHeap->pos[lastNode->v] = 0;

	// Reduce heap size and heapify root
	--minHeap->size;
	minHeapify(minHeap, 0);

	return root;
}

// Function to decreasy dist value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int dist)
{
	// Get the index of v in heap array
	int i = minHeap->pos[v];

	// Get the node and update its dist value
	minHeap->array[i]->dist = dist;

	// Travel up while the complete tree is not hepified.
	// This is a O(Logn) loop
	while (i && minHeap->array[i]->dist < minHeap->array[(i - 1) / 2]->dist)
	{
		// Swap this node with its parent
		minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
		minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
		swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);

		// move to parent index
		i = (i - 1) / 2;
	}
}

// A utility function to check if a given vertex
// 'v' is in min heap or not
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
	return true;
return false;
}
int loca[mxmn];
// A utility function used to print the solution

// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
int dp[200000];
void printArr(int dist[], int n)
{
	vector<pair<int,int> > pt;
	for (int i = 0; i < n; ++i)
		pt.push_back(make_pair(dist[i],i));
	sort(pt.begin(),pt.end());
	int wt = n-2;
	memset(dp,-1,2*n+2);
	for(int i=0;i<n;i++)
	{
		if(pt[i].first==0)
			continue;
		dp[loca[pt[i].second]] = wt--;
	}
	for(int i=n-2;i>=0;i--)
	{
		if(dp[i]!=-1)
		cout<<dp[i]<<"\n";
	}
}
void dijkstra(struct Graph* graph, int src)
{
	int V = graph->V;// Get the number of vertices in graph
	int dist[V];	 // dist values used to pick minimum weight edge in cut

	// minHeap represents set E
	struct MinHeap* minHeap = createMinHeap(V);

	// Initialize min heap with all vertices. dist value of all vertices
	for (int v = 0; v < V; ++v)
	{
		dist[v] = INT_MAX;
		minHeap->array[v] = newMinHeapNode(v, dist[v]);
		minHeap->pos[v] = v;
	}

	// Make dist value of src vertex as 0 so that it is extracted first
	minHeap->array[src] = newMinHeapNode(src, dist[src]);
	minHeap->pos[src] = src;
	dist[src] = 0;
	decreaseKey(minHeap, src, dist[src]);

	// Initially size of min heap is equal to V
	minHeap->size = V;

	// In the followin loop, min heap contains all nodes
	// whose shortest distance is not yet finalized.
	while (!isEmpty(minHeap))
	{
		// Extract the vertex with minimum distance value
		struct MinHeapNode* minHeapNode = extractMin(minHeap);
		int u = minHeapNode->v; // Store the extracted vertex number

		// Traverse through all adjacent vertices of u (the extracted
		// vertex) and update their distance values
		struct AdjListNode* pCrawl = graph->array[u].head;
		while (pCrawl != NULL)
		{
			int v = pCrawl->dest;

			// If shortest distance to v is not finalized yet, and distance to v
			// through u is less than its previously calculated distance
			if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
										pCrawl->weight + dist[u] < dist[v])
			{
				dist[v] = dist[u] + pCrawl->weight;

				// update distance value in min heap also
				decreaseKey(minHeap, v, dist[v]);
			}
			pCrawl = pCrawl->next;
		}
	}
	 printArr(dist,V);
}
void solve()
{
	int n;
	cin>>n;
	int u,v;
	struct Graph* graph = createGraph(n);
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		loca[v-1] = i;
		addEdge(graph, --u, --v, 1);
		vd[u].push_back(v);
		vd[v].push_back(u);
	}
	dijkstra(graph, 0);
}
signed main()
{
	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
//	cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[200000];
const int mxN = 2e5;
vector<int> adj[mxN];
void solve()
{
	int n;
	cin>>n;
	memset(dpp,-1,100004);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[200000];
const int mxN = 2e5;
std::vector<int> adj[mxN];
void solve()
{
	int n;
	cin>>n;
	memset(dpp,-1,mxN);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
	//		cout<<adj[i][j]<<" ";
			dpp[adj[i][j]] = j;
		}
	//	cout<<"\n";
		int cnt= 3;
		for(int k=0;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[200000];
const int mxN = 1e5;
vector<int> adj[mxN+10];
void solve()
{
	int n;
	cin>>n;
	memset(dpp,-1,100004);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
	//		cout<<adj[i][j]<<" ";
			dpp[adj[i][j]] = j;
		}
	//	cout<<"\n";
		int cnt= 3;
		for(int k=0;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	scanf("%d",&n);
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j++;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
// 	#ifndef LINE_JUDGE
  //  // for getting input from input.txt
   // /freopen("input.txt", "r", stdin);
   // // for writing output to output.txt
  //  freopen("output.txt", "w", stdout);
   // #endif
	//int t = 1;
///	while(t--)
//	{
		solve();
	//}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 100008;
int dpp[mxN];
vector<int> adj[mxN];
void solve()
{
	int n;
	cin>>n;
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	while(t--)
	{
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	bool boo[n+1]= {0};
	scanf("%d",&n);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j;
			boo[adj[i][j]] = 1;
		}
		int cnt= j;
		for(int k=0;k<n-1;k++)
		{
			if(!boo[k])
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	solve();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 1e5;
int dpp[mxN+10];
std::vector<int> adj[mxN+10];
void solve()
{
	int n;
	cin>>n;
	memset(dpp,-1,n+2);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<3;j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= 3;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{		if(dpp[k]!=-1)
					cout<<dpp[k]<<"\n";
		}
		return;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	//cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	memset(dpp,-1,100005);
	scanf("%d",&n);
	int u,v;
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		adj[u].push_back(i);
		adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j;
		}
		int cnt= j;
		for(int k=0;k<n-1;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=0;k<n-1;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
//	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	solve();
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
const int mxN = 100008;
int dpp[100005];
vector<int> adj[100005];
int solve()
{
	int n;
	cin>>n;
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
	//	adj[u].push_back(i);
	//	adj[v].push_back(i);
	}
	int j;
	for(int i=1;i<=n;i++)
	{
		if(adj[i].size()<=2)
			continue;
		for(j=0;j<adj[i].size();j++)
		{
			dpp[adj[i][j]] = j++;
		}
		int cnt= 3;
		for(int k=1;k<n;k++)
		{
			if(dpp[k]==-1)
				dpp[k] = cnt++;
		}
		for(int k=1;k<n;k++)
		{
			cout<<dpp[k]<<"\n";
		}
		return 0;
	}
	for(int i=0;i<n-1;i++)
	{
		cout<<i<<"\n";
	}
	return 0;
}
signed main()
{
	fastio
 	#ifndef LINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
	while(t--)
	{
		solve();
	}
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define int long long int
#define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define mxmn 100010
vector <int> vd[mxmn];
struct AdjListNode
{
	int dest;
	int weight;
	struct AdjListNode* next;
};

// A structure to represent an adjacency list
struct AdjList
{
	struct AdjListNode *head; // pointer to head node of list
};

// A structure to represent a graph. A graph is an array of adjacency lists.
// Size of array will be V (number of vertices in graph)
struct Graph
{
	int V;
	struct AdjList* array;
};

// A utility function to create a new adjacency list node
struct AdjListNode* newAdjListNode(int dest, int weight)
{
	struct AdjListNode* newNode =
			(struct AdjListNode*) malloc(sizeof(struct AdjListNode));
	newNode->dest = dest;
	newNode->weight = weight;
	newNode->next = NULL;
	return newNode;
}

// A utility function that creates a graph of V vertices
struct Graph* createGraph(int V)
{
	struct Graph* graph = (struct Graph*) malloc(sizeof(struct Graph));
	graph->V = V;

	// Create an array of adjacency lists. Size of array will be V
	graph->array = (struct AdjList*) malloc(V * sizeof(struct AdjList));

	// Initialize each adjacency list as empty by making head as NULL
	for (int i = 0; i < V; ++i)
		graph->array[i].head = NULL;

	return graph;
}

// Adds an edge to an undirected graph
void addEdge(struct Graph* graph, int src, int dest, int weight)
{
	// Add an edge from src to dest. A new node is added to the adjacency
	// list of src. The node is added at the beginning
	struct AdjListNode* newNode = newAdjListNode(dest, weight);
	newNode->next = graph->array[src].head;
	graph->array[src].head = newNode;

	// Since graph is undirected, add an edge from dest to src also
	newNode = newAdjListNode(src, weight);
	newNode->next = graph->array[dest].head;
	graph->array[dest].head = newNode;
}

// Structure to represent a min heap node
struct MinHeapNode
{
	int v;
	int dist;
};

// Structure to represent a min heap
struct MinHeap
{
	int size;	 // Number of heap nodes present currently
	int capacity; // Capacity of min heap
	int *pos;	 // This is needed for decreaseKey()
	struct MinHeapNode **array;
};

// A utility function to create a new Min Heap Node
struct MinHeapNode* newMinHeapNode(int v, int dist)
{
	struct MinHeapNode* minHeapNode =
		(struct MinHeapNode*) malloc(sizeof(struct MinHeapNode));
	minHeapNode->v = v;
	minHeapNode->dist = dist;
	return minHeapNode;
}

// A utility function to create a Min Heap
struct MinHeap* createMinHeap(int capacity)
{
	struct MinHeap* minHeap =
		(struct MinHeap*) malloc(sizeof(struct MinHeap));
	minHeap->pos = (int *)malloc(capacity * sizeof(int));
	minHeap->size = 0;
	minHeap->capacity = capacity;
	minHeap->array =
		(struct MinHeapNode**) malloc(capacity * sizeof(struct MinHeapNode*));
	return minHeap;
}

// A utility function to swap two nodes of min heap. Needed for min heapify
void swapMinHeapNode(struct MinHeapNode** a, struct MinHeapNode** b)
{
	struct MinHeapNode* t = *a;
	*a = *b;
	*b = t;
}

// A standard function to heapify at given idx
// This function also updates position of nodes when they are swapped.
// Position is needed for decreaseKey()
void minHeapify(struct MinHeap* minHeap, int idx)
{
	int smallest, left, right;
	smallest = idx;
	left = 2 * idx + 1;
	right = 2 * idx + 2;

	if (left < minHeap->size &&
		minHeap->array[left]->dist < minHeap->array[smallest]->dist )
	smallest = left;

	if (right < minHeap->size &&
		minHeap->array[right]->dist < minHeap->array[smallest]->dist )
	smallest = right;

	if (smallest != idx)
	{
		// The nodes to be swapped in min heap
		MinHeapNode *smallestNode = minHeap->array[smallest];
		MinHeapNode *idxNode = minHeap->array[idx];

		// Swap positions
		minHeap->pos[smallestNode->v] = idx;
		minHeap->pos[idxNode->v] = smallest;

		// Swap nodes
		swapMinHeapNode(&minHeap->array[smallest], &minHeap->array[idx]);

		minHeapify(minHeap, smallest);
	}
}

// A utility function to check if the given minHeap is ampty or not
int isEmpty(struct MinHeap* minHeap)
{
	return minHeap->size == 0;
}

// Standard function to extract minimum node from heap
struct MinHeapNode* extractMin(struct MinHeap* minHeap)
{
	if (isEmpty(minHeap))
		return NULL;

	// Store the root node
	struct MinHeapNode* root = minHeap->array[0];

	// Replace root node with last node
	struct MinHeapNode* lastNode = minHeap->array[minHeap->size - 1];
	minHeap->array[0] = lastNode;

	// Update position of last node
	minHeap->pos[root->v] = minHeap->size-1;
	minHeap->pos[lastNode->v] = 0;

	// Reduce heap size and heapify root
	--minHeap->size;
	minHeapify(minHeap, 0);

	return root;
}

// Function to decreasy dist value of a given vertex v. This function
// uses pos[] of min heap to get the current index of node in min heap
void decreaseKey(struct MinHeap* minHeap, int v, int dist)
{
	// Get the index of v in heap array
	int i = minHeap->pos[v];

	// Get the node and update its dist value
	minHeap->array[i]->dist = dist;

	// Travel up while the complete tree is not hepified.
	// This is a O(Logn) loop
	while (i && minHeap->array[i]->dist < minHeap->array[(i - 1) / 2]->dist)
	{
		// Swap this node with its parent
		minHeap->pos[minHeap->array[i]->v] = (i-1)/2;
		minHeap->pos[minHeap->array[(i-1)/2]->v] = i;
		swapMinHeapNode(&minHeap->array[i], &minHeap->array[(i - 1) / 2]);

		// move to parent index
		i = (i - 1) / 2;
	}
}

// A utility function to check if a given vertex
// 'v' is in min heap or not
bool isInMinHeap(struct MinHeap *minHeap, int v)
{
if (minHeap->pos[v] < minHeap->size)
	return true;
return false;
}
int loca[mxmn];
// A utility function used to print the solution

// The main function that calulates distances of shortest paths from src to all
// vertices. It is a O(ELogV) function
int dp[200000];
int dpp[200000];
void printArr(int dist[], int n,int vaj)
{
	vector<pair<int,int> > pt;
	for (int i = 0; i < n; ++i)
		pt.push_back(make_pair(dist[i],i));
	sort(pt.begin(),pt.end());
//	for(int i=0;i<n;i++)
//	{
//		cout<<pt[i].first<<" "<<pt[i].second<<"\n";
//	}
	int wt = n-2;
	memset(dp,-1,2*n+2);
	for(int i=n-1;i>=1;i--)
	{
		if(pt[i].first==0)
			continue;
		if(dpp[loca[pt[i].second]-1]==0)
			dpp[loca[pt[i].second]-1] = vaj++;
	}
}
void dijkstra(struct Graph* graph, int src,int vaj)
{
	int V = graph->V;// Get the number of vertices in graph
	int dist[V];	 // dist values used to pick minimum weight edge in cut

	// minHeap represents set E
	struct MinHeap* minHeap = createMinHeap(V);

	// Initialize min heap with all vertices. dist value of all vertices
	for (int v = 0; v < V; ++v)
	{
		dist[v] = INT_MAX;
		minHeap->array[v] = newMinHeapNode(v, dist[v]);
		minHeap->pos[v] = v;
	}

	// Make dist value of src vertex as 0 so that it is extracted first
	minHeap->array[src] = newMinHeapNode(src, dist[src]);
	minHeap->pos[src] = src;
	dist[src] = 0;
	decreaseKey(minHeap, src, dist[src]);

	// Initially size of min heap is equal to V
	minHeap->size = V;

	// In the followin loop, min heap contains all nodes
	// whose shortest distance is not yet finalized.
	while (!isEmpty(minHeap))
	{
		// Extract the vertex with minimum distance value
		struct MinHeapNode* minHeapNode = extractMin(minHeap);
		int u = minHeapNode->v; // Store the extracted vertex number

		// Traverse through all adjacent vertices of u (the extracted
		// vertex) and update their distance values
		struct AdjListNode* pCrawl = graph->array[u].head;
		while (pCrawl != NULL)
		{
			int v = pCrawl->dest;

			// If shortest distance to v is not finalized yet, and distance to v
			// through u is less than its previously calculated distance
			if (isInMinHeap(minHeap, v) && dist[u] != INT_MAX &&
										pCrawl->weight + dist[u] < dist[v])
			{
				dist[v] = dist[u] + pCrawl->weight;

				// update distance value in min heap also
				decreaseKey(minHeap, v, dist[v]);
			}
			pCrawl = pCrawl->next;
		}
	}
	 printArr(dist,V,vaj);
}
void solve()
{
	int n;
	cin>>n;
	int u,v;
	struct Graph* graph = createGraph(n);
	for(int i=0;i<n-1;i++)
	{
		cin>>u>>v;
		loca[v-1] = i+1;
		addEdge(graph, u-1, v-1, 1);
		vd[--u].push_back(--v);
	}
	int vaj = 0;
	int cnt = 0;
	for(int i=0;i<n;i++)
	{
		if(vd[i].size()==0 && loca[i]!=0)
		{
			cnt++;
			dpp[loca[i]-1] = vaj++;
		}
	}
	vaj = cnt;
	dijkstra(graph,0,vaj);
	for(int i=0;i<n;i++)
	{
		if(dpp[i]<=(n-2))
		cout<<dpp[i]<<"\n";
	}
	//dijkstra(graph, 0);
}
signed main()
{
	fastio
 	#ifndef ONLINE_JUDGE
    // for getting input from input.txt
    freopen("input.txt", "r", stdin);
    // for writing output to output.txt
    freopen("output.txt", "w", stdout);
    #endif
	int t = 1;
//	cin>>t;
	while(t--)
	{
		solve();
	}
	cin.clear();
	cin.get();
	return 0;
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	bool cek[100005];
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<adj[node].size();i++){
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
bool cek[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	if(n==2){
		cout<<0<<endl;
		return 0;
	}
	memset(ans,-1,sizeof ans);
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		//Scout<<node<<" ";
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<adj[node].size();i++){
			//cout<<"jo"<<endl;
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	bool cek[100005];
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(adj[node].size()!=1){
		//Scout<<node<<" ";
		/*if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}*/
		for(int i=0;i<2;i++){
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	ans[adj[node][0].second]=1;
	tmp++;
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
bool cek[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		//Scout<<node<<" ";
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<adj[node].size();i++){
			//cout<<"jo"<<endl;
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	bool cek[100005];
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		//Scout<<node<<" ";
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<2;i++){
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	bool cek[100005];
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		//Scout<<node<<" ";
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<adj[node].size();i++){
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include<bits/stdc++.h>

using namespace std;

int n,u,v,ans[100005];
vector <pair<int,int> >adj[100005];
int main(){
	ios_base::sync_with_stdio(NULL);
	cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>u>>v;
		adj[u].push_back({v,i});
		adj[v].push_back({u,i});
	}
	memset(ans,-1,sizeof ans);
	bool cek[100005];
	int node;
	for(int i=1;i<=n;i++){
		if(adj[i].size()==1){
			cek[i]=1;
			ans[adj[i][0].second]=0;
			node=adj[i][0].first;
			cek[node]=1;
			break;
		}
	}
	int tmp=n-2;
	while(true){
		cout<<node<<" ";
		if(adj[node].size()==1){
			ans[adj[node][0].second]=1;
			tmp++;
			break;
		}
		for(int i=0;i<adj[node].size();i++){
			if(!cek[adj[node][i].first]){
				ans[adj[node][i].second]=tmp;
				node=adj[node][i].first;
				cek[node]=1;
				tmp--;
				break;
			}
		}
	}
	for(int i=1;i<n;i++){
		if(ans[i]==-1){
			cout<<tmp<<endl;
			tmp--;
		}
		else{
			cout<<ans[i]<<endl;
		}
	}
}


#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
typedef pair<int,int> pii;
vector<pii> edg[maxn];
int ans[maxn];
int main(){
    int n;
    cin>>n;
    for(int i=1,u,v;i<=n-1;i++){
        cin>>u>>v;
        edg[u].emplace_back(v,i);
        edg[v].emplace_back(u,i);
        ans[i]=-1;
    }
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(edg[i].size()>=3){
            for(auto j:edg[i]){
                ans[j.second]=cnt++;
            }
            for(int j=1;j<=n;j++){
                if(ans[j]==-1)
                    ans[j]=cnt++;
            }
            for(int j=1;j<n;j++){
                cout<<ans[j]<<"\n";
            }
            return 0;
        }
    }
    for(int i=1;i<n;i++)cout<<i-1<<"\n";
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int M=110000;

vector<vector<int>> e(M);
vector<pair<int,int>> vv;

map<pair<int,int>,int> m;

int main()
{
    int n;cin>>n;
    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
        vv.push_back(make_pair(u,v));
    }
    int num=1;
    for(int i=0;i<n;i++){
    	if(e[i].size()==1){
    		pair<int,int> p1=make_pair(i,e[i][0]);
    		pair<int,int> p2=make_pair(e[i][0],i);
    		if(!m[p1])
    			m[p1]=m[p2]=num++;
    	}
    }
    for(int i=0;i<n;i++){
    	if(e[i].size()!=1){
    		for(int j:e[i]){
    			pair<int,int> p1=make_pair(i,j);
    			pair<int,int> p2=make_pair(j,i);
    			if(!m[p1])
    				m[p1]=m[p2]=num++;
    		}
    	}
    }
	for(auto i:vv){
		cout<<m[i]-1<<endl;
	}
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int M=110000;
typedef pair<int,int> pii;

vector<vector<int>> e(M);
vector<int> siz(M);

vector<pii> a;
map<pii,int> m;

int main()
{
    int n;cin>>n;

    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        --u,--v;
        e[u].push_back(v);
        e[v].push_back(u);
        a.emplace_back(u,v);
    }

    for(int i=0;i<n;i++) siz[i]=i;
    sort(siz.begin(),siz.begin()+n,[&](int a,int b){
    	return e[a].size()<e[b].size();
    });

    int num=1;
    for(int i=0;i<n;i++){
        for(int j:e[siz[i]]){
            pii p1=make_pair(siz[i],j);
            pii p2=make_pair(j,siz[i]);
            if(!m[p1])//如果该边没有编号
                m[p1]=m[p2]=num++;
        }
    }

    for(auto i:a)
        cout<<m[i]-1<<endl;

    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int M=110000;

vector<vector<int>> e(M);
vector<pair<int,int>> vv;

map<pair<int,int>,int> m;

int main()
{
    int n;cin>>n;
    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        e[u].push_back(v);
        e[v].push_back(u);
        vv.push_back(make_pair(u,v));
    }
    int num=1;
    for(int i=1;i<=n;i++){
    	if(e[i].size()==1){
    		for(int j:e[i]){
    			pair<int,int> p1=make_pair(i,j);
    			pair<int,int> p2=make_pair(j,i);
    			if(!m[p1])
    				m[p1]=m[p2]=num++;
    		}
    	}
    }
    for(int i=1;i<=n;i++){
    	if(e[i].size()!=1){
    		for(int j:e[i]){
    			pair<int,int> p1=make_pair(i,j);
    			pair<int,int> p2=make_pair(j,i);
    			if(!m[p1])
    				m[p1]=m[p2]=num++;
    		}
    	}
    }
	for(auto i:vv){
		cout<<m[i]-1<<endl;
	}
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int M=110000;

vector<vector<int>> e(M);
vector<pair<int,int>> vv;

map<pair<int,int>,int> m;

int main(){
    int n;cin>>n;
    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        --u,--v;
        e[u].push_back(v);
        e[v].push_back(u);
        vv.push_back(make_pair(u,v));
    }
    int num=1;
    for(int i=0;i<n;i++){
    	if(e[i].size()==1){
    		pair<int,int> p1=make_pair(i,e[i][0]);
    		pair<int,int> p2=make_pair(e[i][0],i);
    		if(!m[p1])
    			m[p1]=m[p2]=num++;
    	}
    }
    for(int i=0;i<n;i++){
    	if(e[i].size()!=1){
    		pair<int,int> p1=make_pair(i,e[i][0]);
    		pair<int,int> p2=make_pair(e[i][0],i);
    		if(!m[p1])
    			m[p1]=m[p2]=num++;
    	}
    }
	for(auto i:vv){
		cout<<m[i]-1<<endl;
	}
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

const int M=110000;

vector<vector<int>> e(M);
vector<pair<int,int>> vv;

struct A{
	int v,num;
}a[M];

int n;

map<pair<int,int>,int> m;

bool cmp(A a,A b){
	return a.v<b.v;
}

void dfs1(int u,int pre){
    for(int v:e[u]){
        if(v!=pre){
            dfs1(v,u);
            a[u].v+=a[v].v;
        }
    }
}

int main(){
    cin>>n;
    for(int i=0;i<n;i++){
        a[i].v=1;
        a[i].num=i;
    }
    for(int i=0;i<n-1;i++){
        int u,v;cin>>u>>v;
        --u,--v;
        e[u].push_back(v);
        e[v].push_back(u);
        vv.push_back(make_pair(u,v));
    }
    dfs1(0,-1);
    sort(a,a+n,cmp);
	int nn=1;
	for(int i=0;i<n;i++){
		for(int j:e[a[i].num]){
			pair<int,int> p1,p2;
			p1=make_pair(a[i].num,j);
			p2=make_pair(j,a[i].num);
			if(!m[p1]) m[p1]=m[p2]=nn++;
		}
	}
	for(auto i:vv){
		cout<<m[i]-1<<endl;
	}
    return 0;
}


#include <bits/stdc++.h>
using namespace std;

vector<pair<int,int>> v,v2;
map<pair<int,int>,int> m;

bool cmp(pair<int,int> a,pair<int,int> b){
	return a.first==b.first ? a.second<b.second : a.first<b.first ;
}

int main()
{
	int n;cin>>n;
	for(int i=0;i<n-1;i++){
		int a,b;cin>>a>>b;
		v.push_back(make_pair(a,b));
		if(a>b) swap(a,b);
		v2.push_back(make_pair(a,b));
	}
	sort(v2.begin(),v2.end(),cmp);
	m[v2[0]]=0;
	m[v2[v2.size()-1]]=n-2;
	for(int i=1;i<int(v2.size()-1);i++){
		m[v2[i]]=i;
	}
	for(auto i:v)
		cout<<m[i]<<endl;
	return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=0;i<t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}
for(int j=1;j<=t;j++)
{
for(int i=1;i<=t;i++)
{

	if(a[i]==j&&vis[p[i]]==0)
	{
		// cout<<i<<endl;
		ans[p[i]]=num++;
		vis[p[i]]=1;
	}
}
}
  for(int i=0;i<t-1;i++)
  	{
  		if(vis[p[i]])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=0;i<t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}
for(int j=1;j<=t;j++)
{
for(int i=1;i<=t;i++)
{

	if(a[i]==j&&vis[p[i]]==0)
	{
		// cout<<i<<endl;
		ans[p[i]]=num++;
		vis[p[i]]=1;
	}
}
}
  for(int i=0;i<t-1;i++)
  	{
  		if(vis[i])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <set>
#include <map>
#include <queue>

using namespace std;

typedef long long ll;

const int INF = 2139062143;

template <typename T> void read (T &x) {
    x = 0; bool f = 1; char ch;
    do {ch = getchar(); if (ch == '-') f = 0;} while (ch > '9' || ch < '0');
    do {x = x * 10 + ch - '0'; ch = getchar();} while (ch >= '0' && ch <= '9');
    x = f ? x : -x;
}

template <typename T> void write (T x) {
    if (x < 0) x = ~x + 1, putchar ('-');
    if (x > 9) write (x / 10);
    putchar (x % 10 + '0');
}

const int N = 1e5 + 7;

struct Node {
    int to, nxt;
} edge[N << 1];

struct EDGE {
    int u, v, id, ret, ans;
} e[N];

bool cmp (EDGE a, EDGE b) {
    return a.ret < b.ret;
}

bool cmp1 (EDGE a, EDGE b) {
    return a.id < b.id;
}

int n, E, in[N], buk[N], head[N];

inline void addedge (int u, int v) {
    edge[++E].to = v;
    edge[E].nxt = head[u];
    head[u] = E;
}

int main () {
    read (n);
    for (int i = 1, u, v; i < n; i ++ ) {
        read (u); read (v);
        e[i].u = u; e[i].v = v; e[i].id = i; in[u] ++ ; in[v] ++ ;
    }
    for (int i = 1; i < n; i ++ ) e[i].ret = min (in[e[i].u], in[e[i].v]);
    sort (e + 1, e + n, cmp);
    for (int i = 1; i < n; i ++ ) e[i].ans = i;
    sort (e + 1, e + n, cmp1);
    for (int i = 1; i < n; i ++ ) printf ("%d\n", e[i].ans - 1);
    return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=0;i<t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}
for(int i=1;i<=t;i++)
{
	if(a[i]==1)
	{
		ans[p[i]]=num++;
		vis[p[i]]=1;
	}
}
  for(int i=0;i<t-1;i++)
  	{
  		if(vis[i])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int len;
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=0;i<t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}
for(int j=1;j<=t;j++)
{
	if(len==t-1)break;
for(int i=1;i<=t;i++)
{

	if(a[i]==j&&vis[p[i]]==0)
	{
		len++;
		ans[p[i]]=num++;
		vis[p[i]]=1;
	}
}
}
  for(int i=0;i<t-1;i++)
  	{
  		if(vis[i])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int len;
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=1;i<=t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}
for(int j=1;j<=t;j++)
{
if(a[j]==1)
{
	ans[p[j]]=num++;
	vis[p[j]]=1;
}
}
  for(int i=1;i<=t-1;i++)
  	{
  		if(vis[i])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include <iostream>
#include <string>
#include <cstring>
#include<map>
using namespace std;
int a[100020];
int p[10020];
int vis[10020];
int ans[10020];
int num;
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int num=0;
int t;cin>>t;
for(int i=0;i<t-1;i++)
{
	int x,y;
	cin>>x>>y;
	p[x]=p[y]=i;
	a[x]++;
	a[y]++;

}

for(int i=1;i<=t;i++)
{

	if(a[i]==1&&vis[p[i]]==0)
	{
		// cout<<i<<endl;
		ans[p[i]]=num++;
		vis[p[i]]=1;
	}
}

  for(int i=0;i<t-1;i++)
  	{
  		if(vis[i])
  		cout<<ans[i]<<endl;
  	else cout<<num++<<endl;

  	}

    return 0;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
int ss=1;
int sss=nodes[ss].size();
for(int i=1;i<=n;i++){
    if(nodes[i].size()>sss){
        sss=nodes[i].size();
        ss=i;
    }
}
bfs.push(ss);
visited[ss]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        E[min(i,s)][max(i,s)]=*z.begin();
        z.erase(z.begin());
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
    E[x][y]=-1;
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
bool g=0;
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(nodes[i].size()==1){
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);}
        bfs.push(i);
    }
}
}
for(int i=0;i<edges.size();i++){
    if(E[edges[i].first][edges[i].second]==-1){
        E[edges[i].first][edges[i].second]=*z.begin();
        z.erase(z.begin());
    }
}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
for(auto i:nodes[s]){
    int x=1;
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(z.size()>=x){
            for(int i=1;i<=x;i++){
                it++;
            }
}
x++;
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        E[min(i,s)][max(i,s)]=*z.begin();
        z.erase(z.begin());
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
for(auto i:nodes[s]){
    int x=1;
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(z.size()>=x){
            for(int i=1;i<=x;i++){
                it++;
            }
}
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
bool g=0;
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(g==1) {
            it=z.end();
            it--;
        }
        g=!g;
        E[min(i,s)][max(i,s)]=*z.begin();
        z.erase(z.begin());
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(z.size()!=1){
            it++;}
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
  int x=0;
for(auto i:nodes[s]){
    if(!visited[i]){
       x++;
    }
}
if(x>2){
    for(auto i:nodes[s]){
    if(!visited[i]){
      visited[i]=1;
        auto it=z.begin();
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
}}}
else {
    x=-1;
    if(z.size()>2){
    auto it=z.begin();
    it++;
    x=*it;
    z.erase(it);}
    for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
}
}
if(x!=-1)
z.insert(x);
}
}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
bool g=0;
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(g==1) {
            it=z.end();
            it--;
        }
        if(g==0)g=1;
        else g=0;
        E[min(i,s)][max(i,s)]=*z.begin();
        z.erase(z.begin());
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
bool g=0;
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(g==1) {
            it=z.end();
            it--;
        }
        if(g==0)g=1;
        else g=0;
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);
        bfs.push(i);
    }
}

}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
#define mp make_pair
#define mod 1000000007
set<int>z;
unordered_map<int,int>visited;
unordered_map<int,vector<int>>nodes;
unordered_map<int,unordered_map<int,int>>E;
vector<pair<int,int>>edges;
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int n;
cin>>n;
for(int i=0;i<n-1;i++)z.insert(i);
for(int i=0;i<n-1;i++){
    int x,y;
    cin>>x>>y;
    nodes[x].pb(y);
    nodes[y].pb(x);
    if(x>y)swap(x,y);
    edges.pb(mp(x,y));
    E[x][y]=-1;
}
queue<int>bfs;
bfs.push(1);
visited[1]=1;
while(bfs.size()){
int s=bfs.front();
bfs.pop();
bool g=0;
for(auto i:nodes[s]){
    if(!visited[i]){
        visited[i]=1;
        auto it=z.begin();
        if(nodes[s].size()==2){
        E[min(i,s)][max(i,s)]=*it;
        z.erase(it);}
        bfs.push(i);
    }
}
}
for(int i=0;i<edges.size();i++){
    if(E[edges[i].first][edges[i].second]==-1){
        E[edges[i].first][edges[i].second]=*z.begin();
        z.erase(z.begin());
    }
}
for(int i=0;i<edges.size();i++){
    cout<<E[edges[i].first][edges[i].second]<<'\n';
}
return 0;}


#include<bits/stdc++.h>

#define endl "\n"
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;

constexpr int N = 1e5 + 5;

int n, cur = 0;
vector<pii> gr[N];
vector<int> ans;
bool used[N];

void Solve() {
  cin >> n;
  ans.assign(n, -1);
  for (int i = 1, a, b; i < n; i++) {
    cin >> a >> b;
    gr[a].emplace_back(b, i);
    gr[b].emplace_back(a, i);
  }
  queue<int> q;
  for (int i = 1; i <= n; i++)
    if (gr[i].size() == 1)
      q.push(i);
  while(q.size()) {
    int v = q.front();
    used[v] = 1;
    q.pop();
    for (auto [u, id]: gr[v]) {
      if (ans[id] == -1) {
        if (!used[u])
          q.push(u), used[u] = 1;
        ans[id] = cur++;

      }
    }
  }
  for (int i = 1; i < n; i++)
    cout << ans[i] << endl;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);

  //auto start = chrono::high_resolution_clock::now();
    Solve();
  //auto end = chrono::high_resolution_clock::now();
  //cout << endl << (chrono::duration_cast<chrono::duration<double>>(end - start)).count();
  return 0;
}


#include<bits/stdc++.h>

#define endl "\n"
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;

constexpr int N = 1e5 + 5;

int n, cur = 0;
vector<pii> gr[N];
vector<int> ans;

void Solve() {
  cin >> n;
  ans.assign(n, -1);
  for (int i = 1, a, b; i < n; i++) {
    cin >> a >> b;
    gr[a].emplace_back(b, i);
    gr[b].emplace_back(a, i);
  }
  queue<int> q;
  for (int i = 1; i <= n; i++)
    if (gr[i].size() == 1)
      q.push(i);
  while(q.size()) {
    int v = q.front();
    q.pop();
    for (auto [u, id]: gr[v]) {
      if (ans[id] == -1) {
        q.push(u);
        ans[id] = cur++;
      }
    }
  }
  for (int i = 1; i < n; i++)
    cout << ans[i] << endl;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);

  //auto start = chrono::high_resolution_clock::now();
    Solve();
  //auto end = chrono::high_resolution_clock::now();
  //cout << endl << (chrono::duration_cast<chrono::duration<double>>(end - start)).count();
  return 0;
}


#include<bits/stdc++.h>

#define endl "\n"
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;

constexpr int N = 1e5 + 5;

int n, cur = 0;
vector<pii> gr[N];
vector<int> ans;

void Solve() {
  cin >> n;
  ans.assign(n, -1);
  for (int i = 1, a, b; i < n; i++) {
    cin >> a >> b;
    gr[a].emplace_back(b, i);
    gr[b].emplace_back(a, i);
  }
  queue<int> q;
  for (int i = 1; i <= n; i++)
    if (gr[i].size() == 1)
      q.push(i);
  while(q.size()) {
    int v = q.front();
    q.pop();
    for (auto [u, id]: gr[v]) {
      if (ans[id] == -1) {
        q.emplace(u);
        ans[id] = cur++;
      }
    }
  }
  for (int i = 1; i < n; i++)
    cout << ans[i] << endl;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);

  //auto start = chrono::high_resolution_clock::now();
    Solve();
  //auto end = chrono::high_resolution_clock::now();
  //cout << endl << (chrono::duration_cast<chrono::duration<double>>(end - start)).count();
  return 0;
}