#include<stdio.h>
#include<algorithm>
using namespace std;
int n,i,heap[2][100001],w[100001],top[2],t,m;
struct CMP{
    bool operator()(int p,int q){
        return w[p]>w[q];
    }
};
int main()
{
    int a;
    scanf("%d",&n);
    for(i=1;i<=n;i++){
        scanf("%d%d",&a,&w[i]);
        heap[a][top[a]++]=i;
    }
    make_heap(heap[0],heap[0]+top[0],CMP());
    make_heap(heap[1],heap[1]+top[1],CMP());
    for(i=0;i<n-1;i++){
        t=0,m=w[heap[0][0]];if(m>w[heap[1][0]])t=1,m=w[heap[1][0]];
        if(!top[t])t=1-t;
        printf("%d %d %d\n",heap[t][0],heap[1-t][top[1-t]-1],m);
        pop_heap(heap[t],heap[t]+top[t]--,CMP());
        w[heap[1-t][top[1-t]-1]]-=m;
        push_heap(heap[1-t],heap[1-t]+top[1-t],CMP());
    }
    return 0;
}


#include<stdio.h>
#include<algorithm>
using namespace std;
int n,i,heap[2][100001],w[100001],top[2],t,m;
struct CMP{
	bool operator()(int p,int q){
		return w[p]>w[q];
	}
};
int main()
{
	int a;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a,&w[i]);
		heap[a][top[a]++]=i;
	}
	make_heap(heap[0],heap[0]+top[0],CMP());
	make_heap(heap[1],heap[1]+top[1],CMP());
	for(i=0;i<n-1;i++){
		t=0,m=w[heap[0][0]];if(m>w[heap[1][0]])t=1,m=w[heap[1][0]];
		printf("%d %d %d\n",heap[t][0],heap[1-t][max(0,top[1-t]-1)],m);
		pop_heap(heap[t],heap[t]+top[t]--,CMP());
		if(top[1-t]){
			w[heap[1-t][top[1-t]-1]]-=m;
			push_heap(heap[1-t],heap[1-t]+top[1-t],CMP());}
	}
}


#include<stdio.h>
#include<algorithm>
using namespace std;
int n,i,heap[2][100001],w[100001],top[2],t,m;
struct CMP{
	bool operator()(int p,int q){
		return w[p]>w[q];
	}
};
int main()
{
	int a;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a,&w[i]);
		heap[a][top[a]++]=i;
	}
	make_heap(heap[0],heap[0]+top[0],CMP());
	make_heap(heap[1],heap[1]+top[1],CMP());
	for(i=0;i<n-1;i++){
		t=0,m=w[heap[0][0]];if(m>w[heap[1][0]])t=1,m=w[heap[1][0]];
		if(!top[t])t=1-t;
		printf("%d %d %d\n",heap[t][0],heap[1-t][max(0,top[1-t]-1)],m);
		pop_heap(heap[t],heap[t]+top[t]--,CMP());
		if(top[1-t]){
			w[heap[1-t][top[1-t]-1]]-=m;
			push_heap(heap[1-t],heap[1-t]+top[1-t],CMP());}
	}
}


#include<stdio.h>
#include<algorithm>
using namespace std;
int n,i,heap[2][100001],w[100001],top[2],t,m;
struct CMP{
	bool operator()(int p,int q){
		return w[p]>w[q];
	}
};
int main()
{
	int a;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a,&w[i]);
		heap[a][top[a]++]=i;
	}
	make_heap(heap[0],heap[0]+top[0],CMP());
	make_heap(heap[1],heap[1]+top[1],CMP());
	for(i=0;i<n-1;i++){
		t=0,m=w[heap[0][0]];if(m>w[heap[1][0]])t=1,m=w[heap[1][0]];
		printf("%d %d %d\n",heap[t][0],heap[1-t][top[1-t]-1],m);
		pop_heap(heap[t],heap[t]+top[t]--,CMP());
		w[heap[1-t][top[1-t]-1]]-=m;
		push_heap(heap[1-t],heap[1-t]+top[1-t],CMP());
	}
	return 0;
}


#include<stdio.h>
#include<algorithm>
using namespace std;
int n,i,heap[2][100001],w[100001],top[2],t,m;
struct CMP{
	bool operator()(int p,int q){
		return w[p]>w[q];
	}
};
int main()
{
	int a;
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d%d",&a,&w[i]);
		heap[a][top[a]++]=i;
	}
	make_heap(heap[0],heap[0]+top[0],CMP());
	make_heap(heap[1],heap[1]+top[1],CMP());
	for(i=0;i<n-1;i++){
		if(!top[t]||!top[1-t])break;
		t=0,m=w[heap[0][0]];if(m>w[heap[1][0]])t=1,m=w[heap[1][0]];
		printf("%d %d %d\n",heap[t][0],heap[1-t][max(0,top[1-t]-1)],m);
		pop_heap(heap[t],heap[t]+top[t]--,CMP());
		if(top[1-t]){
			w[heap[1-t][top[1-t]-1]]-=m;
			push_heap(heap[1-t],heap[1-t]+top[1-t],CMP());}
	}
}


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long int64;
typedef long double real;
typedef pair<int,int> pii;

#define X first
#define Y second

const int MaxN=100010;

int n;
int c[MaxN],s[MaxN];
set<pii> v[2];

int main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&c[i],&s[i]);
		v[c[i]].insert(make_pair(s[i],i));
	}
	for (int i=1;i<n;++i)
	{
		int w=1;
		if (pii(v[0].begin()->X,-(int)v[0].size())<pii(v[1].begin()->X,-(int)v[1].size())) w=0;
		printf("%d %d %d\n",v[w].begin()->Y,v[w^1].begin()->Y,v[w].begin()->X);
		const_cast<int&>(v[w^1].begin()->X)-=v[w].begin()->X;
		v[w].erase(v[w].begin());
	}
	return 0;
}


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long int64;
typedef long double real;
typedef pair<int,int> pii;

#define X first
#define Y second

const int MaxN=100010;

int n;
int c[MaxN],s[MaxN];
set<pii> v[2];

int main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&c[i],&s[i]);
		v[c[i]].insert(make_pair(s[i],i));
	}
	int x=0;
	int xx=v[0].rbegin()->Y,yy=v[1].rbegin()->Y;
	while (!v[0].empty())
	{
		if (v[0].begin()->X!=0) break;
		++x;
		if (x==n) break;
		printf("%d %d %d\n",v[0].begin()->Y,yy,0);
		v[0].erase(v[0].begin());
	}
	while (!v[1].empty())
	{
		if (v[1].begin()->X!=0) break;
		++x;
		if (x==n) break;
		printf("%d %d %d\n",v[1].begin()->Y,xx,0);
		v[1].erase(v[1].begin());
	}
	for (int i=x+1;i<n;++i)
	{
		int sa=v[0].begin()->X;
		int sb=v[1].begin()->X;
		if (sa<=sb)
		{
			pii p=*v[1].rbegin();
			v[1].erase(p);
			printf("%d %d %d\n",v[0].begin()->Y,p.Y,sa);
			p.X-=sa;
			if (p.X) v[1].insert(p);
			v[0].erase(v[0].begin());
		}
		else
		{
			pii p=*v[0].rbegin();
			v[0].erase(p);
			printf("%d %d %d\n",v[1].begin()->Y,p.Y,sb);
			p.X-=sb;
			if (p.X) v[0].insert(p);
			v[1].erase(v[1].begin());
		}
	}
	return 0;
}


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long int64;
typedef long double real;
typedef pair<int,int> pii;

#define X first
#define Y second

const int MaxN=100010;

int n;
int c[MaxN],s[MaxN];
set<pii> v[2];

int main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&c[i],&s[i]);
		v[c[i]].insert(make_pair(s[i],i));
	}
	for (int i=1;i<n;++i)
	{
		int w=1;
		if (pii(v[0].begin()->X,v[0].size())<pii(v[1].begin()->X,v[1].size())) w=0;
		printf("%d %d %d\n",v[w].begin()->Y,v[w^1].begin()->Y,v[w].begin()->X);
		const_cast<int&>(v[w^1].begin()->X)-=v[w].begin()->X;
		v[w].erase(v[w].begin());
	}
	return 0;
}


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long int64;
typedef long double real;
typedef pair<int,int> pii;

#define X first
#define Y second

const int MaxN=100010;

int n;
int c[MaxN],s[MaxN];
set<pii> v[2];

int main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&c[i],&s[i]);
		v[c[i]].insert(make_pair(s[i],i));
	}
	int x=0;
	int xx=v[0].begin()->Y,yy=v[1].begin()->Y;
	while (!v[0].empty())
	{
		if (v[0].begin()->X!=0) break;
		++x;
		printf("%d %d %d\n",v[0].begin()->Y,yy,0);
		v[0].erase(v[0].begin());
	}
	while (!v[1].empty())
	{
		if (v[1].begin()->X!=0) break;
		++x;
		printf("%d %d %d\n",v[1].begin()->Y,xx,0);
		v[1].erase(v[1].begin());
	}
	for (int i=x+1;i<n;++i)
	{
		int sa=v[0].begin()->X;
		int sb=v[1].begin()->X;
		if (sa<=sb)
		{
			pii p=*v[1].rbegin();
			v[1].erase(p);
			printf("%d %d %d\n",v[0].begin()->Y,p.Y,sa);
			p.X-=sa;
			if (p.X) v[1].insert(p);
			v[0].erase(v[0].begin());
		}
		else
		{
			pii p=*v[0].rbegin();
			v[0].erase(p);
			printf("%d %d %d\n",v[1].begin()->Y,p.Y,sb);
			p.X-=sb;
			if (p.X) v[0].insert(p);
			v[1].erase(v[1].begin());
		}
	}
	return 0;
}


#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<iostream>
#include<sstream>
#include<algorithm>
#include<string>
#include<bitset>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<iomanip>

using namespace std;

typedef long long int64;
typedef long double real;
typedef pair<int,int> pii;

#define X first
#define Y second

const int MaxN=100010;

int n;
int c[MaxN],s[MaxN];
set<pii> v[2];

int main()
{
	cin>>n;
	for (int i=1;i<=n;++i)
	{
		scanf("%d%d",&c[i],&s[i]);
		v[c[i]].insert(make_pair(s[i],i));
	}
	for (int i=1;i<n;++i)
	{
		int sa=v[0].begin()->X;
		int sb=v[1].begin()->X;
		if (sa<=sb)
		{
			pii p=*v[1].rbegin();
			v[1].erase(p);
			printf("%d %d %d\n",v[0].begin()->Y,p.Y,sa);
			p.X-=sa;
			if (p.X) v[1].insert(p);
			v[0].erase(v[0].begin());
		}
		else
		{
			pii p=*v[0].rbegin();
			v[0].erase(p);
			printf("%d %d %d\n",v[1].begin()->Y,p.Y,sb);
			p.X-=sb;
			if (p.X) v[0].insert(p);
			v[1].erase(v[1].begin());
		}
	}
	return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#include<cstdio>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x,num[2];
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
        num[id]=i+1;
    }
    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        s[1-x].insert(a);
    }

    for(i=0;i<2;i++)
    {
        if(!s[i].empty())
          for(set<pair<int,int> >::iterator it=s[i].begin();it!=s[i].end();it++)
             printf("%d %d 0\n",it->second,num[1-i]);
    }

return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
    }

    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        //if(a.first>0)
        s[1-x].insert(a);
    }

return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
    }
    int last=0;
    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        else if(s[0].begin()->first == s[1].begin()->first)x=1-last;
        cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        s[1-x].insert(a);
        last=x;
    }

return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#include<cstdio>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x,num[2];
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
        num[id]=i+1;
    }
    int lstx;

    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        //if(a.first>0)
        s[1-x].insert(a);
        lstx=x;
    }
    s[1-x].erase(s[1-x].begin());

    for(i=0;i<2;i++)
    {
        if(!s[i].empty())
          for(set<pair<int,int> >::iterator it=s[i].begin();it!=s[i].end();it++)
             printf("%d %d 0\n",it->second,num[1-i]);
    }

return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#include<cstdio>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x,num[2];
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
        num[id]=i+1;
    }
    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        if(a.first>0)s[1-x].insert(a);
    }

    for(i=0;i<2;i++)
    {
        if(!s[i].empty())
          for(set<pair<int,int> >::iterator it=s[i].begin();it!=s[i].end();it++)
             printf("%d %d 0\n",it->second,num[1-i]);
    }

return 0;
}


#include<iostream>
#include<set>
#include<algorithm>
#include<cstdio>
#define mp make_pair
using namespace std;
int main()
{
    set<pair<int,int> > s[2];
    int i,j,n,m,id,x,num[2],ans=0;
    cin>>n;
    for(i=0;i<n;i++)
    {
        cin>>id>>x;
        s[id].insert(mp(x,i+1));
        num[id]=i+1;
    }
    while(!s[0].empty() && !s[1].empty())
    {
        x=1;
        if(s[0].begin()->first < s[1].begin()->first)x=0;
        if(ans<n-1)cout<<s[0].begin()->second<< ' ' <<s[1].begin()->second<<' '<<s[x].begin()->first<<endl;
        ans++;
        pair<int,int> a=*s[1-x].begin();
        a.first-=s[x].begin()->first;
        s[x].erase(s[x].begin());
        s[1-x].erase(s[1-x].begin());
        //if(a.first>0)
        s[1-x].insert(a);
    }

    for(i=0;i<2;i++)
    {
        if(!s[i].empty())
          for(set<pair<int,int> >::iterator it=s[i].begin();it!=s[i].end();it++,ans++)
             if(ans<n-1)printf("%d %d 0\n",it->second,num[1-i]);
    }

return 0;
}


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

int pa[100000+5];
int rank[100000+5];
int color[100000+5];
set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)
vector<int> leaders;

int myfind(int u)
{
    while (pa[u] != u) u = pa[u];
    return u;
}

void myunion(int p1, int p2)
{
    if (rank[p1] < rank[p2]) { pa[p1] = p2; }
    else if (rank[p1] > rank[p2]) { pa[p2] = p1; }
    else { pa[p1] = p2; rank[p2]++; }
}

int main()
{
    int n; cin >> n;
    // init
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    leaders.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        color[i] = c;
        if (s > 0)
            bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    //cout << "edges " << edges.size() << endl;
    // now all s[v] is zero
    // connect the components using w(e)=0 edges
    // can only connect different color vertex
    for (int i=0; i<n; ++i) { pa[i] = i; rank[i] = 0; }
    for (int i=0; i<int(edges.size()); ++i) {
        int u, v, p1, p2;
        u = edges[i].second.first;
        v = edges[i].second.second;
        p1 = myfind(u);
        p2 = myfind(v);
        if (p1 != p2) { myunion(p1, p2); }
    }
    // connect everyone to center[0] and center[1]
    int center[2];
    for (int c=0; c<2; ++c) {
        for (int i=0; i<n; ++i) if (color[i] == c) { center[c] = i; break; }
    }

    for (int i=0; i<n; ++i) {
        int p = myfind(i);
        for (int c=0; c<2; ++c) {
            if (color[p] != c && p != myfind(center[c])) {
                myunion(p, center[c]);
                edges.push_back(make_pair(0, pii(p, center[c])));
            }
        }
    }

    if (myfind(center[0]) != myfind(center[1])) {
        myunion(center[0], center[1]);
        edges.push_back(make_pair(0, pii(center[0], center[1])));
    }

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


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)

int main()
{
    int n; cin >> n;
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    assert(edges.size() == n-1);
    for (int i=0; i<int(edges.size()); ++i) {
        cout << 1+edges[i].second.first << ' '
            << 1+edges[i].second.second << ' '
            << edges[i].first << '\n';
    }
}


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

int pa[100000+5];
int rank[100000+5];
int color[100000+5];
set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)
vector<int> leaders;

int myfind(int u)
{
    while (pa[u] != u) u = pa[u];
    return u;
}

void myunion(int p1, int p2)
{
    if (rank[p1] < rank[p2]) { pa[p1] = p2; }
    else if (rank[p1] > rank[p2]) { pa[p2] = p1; }
    else { pa[p1] = p2; rank[p2]++; }
}

int main()
{
    int n; cin >> n;
    // init
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    leaders.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        color[i] = c;
        if (s > 0)
            bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    //cout << "edges " << edges.size() << endl;
    // now all s[v] is zero
    // connect the components using w(e)=0 edges
    // can only connect different color vertex
    for (int i=0; i<n; ++i) { pa[i] = i; rank[i] = 0; }
    for (int i=0; i<int(edges.size()); ++i) {
        int u, v, p1, p2;
        u = edges[i].second.first;
        v = edges[i].second.second;
        p1 = myfind(u);
        p2 = myfind(v);
        if (p1 != p2) { myunion(p1, p2); }
    }
    // connect everyone to center[0] and center[1]
    int center[2];
    for (int c=0; c<2; ++c) {
        for (int i=0; i<n; ++i) if (color[i] == c) { center[c] = i; break; }
    }

    for (int i=0; i<n; ++i) {
        int p = myfind(i);
        for (int c=0; c<2; ++c) {
            int p2 = myfind(center[c]);
            if (color[p] != c && p != p2) {
                myunion(p, p2);
                edges.push_back(make_pair(0, pii(p, center[c])));
            }
        }
    }

    if (myfind(center[0]) != myfind(center[1])) {
        myunion(center[0], center[1]);
        edges.push_back(make_pair(0, pii(center[0], center[1])));
    }

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


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)

int main()
{
    int n; cin >> n;
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    for (int i=0; i<int(edges.size()); ++i) {
        cout << 1+edges[i].second.first << ' '
            << 1+edges[i].second.second << ' '
            << edges[i].first << '\n';
    }
}


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <cassert>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)

int main()
{
    int n; cin >> n;
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    assert(edges.size() == n-1);
    for (int i=0; i<int(edges.size()); ++i) {
        cout << 1+edges[i].second.first << ' '
            << 1+edges[i].second.second << ' '
            << edges[i].first << '\n';
    }
}


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <cassert>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)

int main()
{
    int n; cin >> n;
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    //assert(edges.size() == n-1);
    for (int i=0; i<int(edges.size()); ++i) {
        cout << 1+edges[i].second.first << ' '
            << 1+edges[i].second.second << ' '
            << edges[i].first << '\n';
    }
}


// separate color=0 and 1 into two parts
// edge can go only from one part to the other
// find min s[v] and connect to the max s[w] on the other part
//
// Use heap or BST (stl set) to get min and max and update in O(log n) time
//
// Correctness from induction

#include <cassert>
#include <cstring>
#include <iostream>
#include <set>
#include <vector>
using namespace std;

typedef pair<int,int> pii;

int pa[100000+5];
int rank[100000+5];
set<pii> bipart[2]; // 0 white, 1 black, (s[v], id)
vector<pair<int, pii> > edges;  // weight, (u, v)
vector<int> leaders;

int myfind(int u)
{
    while (pa[u] != u) u = pa[u];
    return u;
}

int main()
{
    int n; cin >> n;
    // init
    for (int c=0; c<2; ++c)
        bipart[c].clear();
    edges.clear();
    leaders.clear();
    for (int i=0; i<n; ++i) {
        int c, s; cin >> c >> s;
        if (s > 0)
            bipart[c].insert(pii(s, i));
    }

    while (!bipart[0].empty()) {
        pii p[2];
        int cmin, s[2];
        for (int c=0; c<2; ++c)
            p[c] = *(bipart[c].begin());
        for (int c=0; c<2; ++c)
            s[c] = p[c].first;
        cmin = s[0] < s[1] ? 0 : 1;

        int cc, ss, id;
        ss = s[cmin];
        id = p[cmin].second;
        cc = cmin;
        bipart[cc].erase(bipart[cc].begin());
        set<pii>::iterator it = bipart[1-cc].end(); --it;
        pii mate = *it; bipart[1-cc].erase(it);
        edges.push_back(make_pair(ss, pii(id, mate.second)));
        mate.first -= ss;
        assert(mate.first >= 0);
        if (mate.first > 0) bipart[1-cc].insert(mate);
    }
    //cout << "edges " << edges.size() << endl;
    // now all s[v] is zero
    // connect the components
    for (int i=0; i<n; ++i) { pa[i] = i; rank[i] = 0; }
    for (int i=0; i<int(edges.size()); ++i) {
        int u, v, p1, p2;
        u = edges[i].second.first;
        v = edges[i].second.second;
        p1 = myfind(u);
        p2 = myfind(v);
        if (p1 != p2) {  // union by rank
            if (rank[p1] < rank[p2]) { pa[p1] = p2; }
            else if (rank[p1] > rank[p2]) { pa[p2] = p1; }
            else { pa[p1] = p2; rank[p2]++; }
        }
    }
    for (int i=0; i<n; ++i) if (i == pa[i]) leaders.push_back(i);
    //assert(edges.size() == n-1);
    for (int i=0; i<int(edges.size()); ++i) {
        cout << 1+edges[i].second.first << ' '
            << 1+edges[i].second.second << ' '
            << edges[i].first << '\n';
    }
    for (int i=1; i<int(leaders.size()); ++i) {
        cout << 1+leaders[i-1] << ' ' << 1+leaders[i] << ' ' << 0 << '\n';
    }
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++){
        if(root(1)!=root(i) && c[1]!=c[i]){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n-1;i++)
        if(v[i]==u[i])
            cout<<i<<endl;
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++){
        if(root(1)!=root(i)){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n,bf,wf;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            bf=i,b.push_back(i);
        else
            wf=i,w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=1;i<=n;i++){
        if(root(i)!=root(bf) && c[bf]!=c[i]){
            v[cnt]=bf,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n;i++){
        if(root(i)!=root(wf) && c[wf]!=c[i]){
            v[cnt]=wf,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n-1;i++)
        if(v[i]==u[i])
            cout<<i<<endl;
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++){
        if(root(1)!=root(i) && c[1]!=c[i]){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    int q=1,d=1000*1000;
    for(int i=1;i<=n-1;i++){
        d=min(d,v[i]);
        d=min(d,u[i]);
        q=max(q,v[i]);
        q=max(q,u[i]);
    }
    if(n==1000)
        cout<<q<<" "<<d<<endl;
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++){
        if(root(1)!=root(i) && c[1]!=c[i]){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f=j+1;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++){
        if(root(1)!=root(i) && c[1]!=c[i]){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    }
    for(int i=1;i<=n-1;i++)
        if(v[i]==u[i]==0)
            cout<<i<<endl;
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <cstring>
#include <iomanip>
#include <set>
#include <map>
using namespace std;
const int maxn=1000*100+100;
vector <int>b,w;
int v[maxn],u[maxn],we[maxn],par[maxn],c[maxn],s[maxn],cnt=1,n;
int  root(int v){
    return (par[v]==v) ? v : par[v]=root(par[v]);
}
void onion(int a,int b){
    par[root(a)]=par[root(b)];
}
int main()
{
    ios_base::sync_with_stdio (false);
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>s[i],par[i]=i;
        if(c[i]==1)
            b.push_back(i);
        else
            w.push_back(i);
    }
    int f=0;
    for(int i=0;i<b.size();i++){
        for(int j=f;j<w.size();j++){
            onion(b[i],w[j]);
            int ans=min(s[b[i]],s[w[j]]);
            v[cnt]=b[i],u[cnt]=w[j],we[cnt]=ans;
            cnt++;
            s[b[i]]-=ans,s[w[j]]-=ans;
            if(s[b[i]]>0)
                f++;
            else
                break;
        }
    }
    for(int i=2;i<=n;i++)
        if(root(1)!=root(i) && c[1]!=c[i]){
            v[cnt]=1,u[cnt]=i,we[cnt]=0,cnt++;
            onion(1,i);
        }
    for(int i=1;i<=n-1;i++)
        cout<<v[i]<<" "<<u[i]<<" "<<we[i]<<endl;

    return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int w, mn, i, j, cnt;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(w){
      if(col[i]) bl.push(edge(i, w));
      else wh.push(edge(i, w));
    }
  }

  cnt = n - 1;
  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
    --cnt;
  }

  for(i = 1; i < n && cnt; ++i){
    if(col[i] != col[n] && find(i) != find(n)){
      p[find(i)] = find(n);
      printf("%d %d 0\n", i, n);
      --cnt;
    }
  }

  for(i = 1; i < n && cnt; ++i){
    if(col[i] != col[n] && find(i) == find(n)){
      for(j = 1; j <= n && cnt; ++j){
        if(col[i] != col[j] && find(i) != find(j)){
          p[find(i)] = find(j);
          printf("%d %d 0\n", i, j);
          --cnt;
        }
      }
    }
  }
  return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int pu, pv, w, mn, i, j;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(col[i]) bl.push(edge(i, w));
    else wh.push(edge(i, w));
  }

  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
  }

  for(i = 1; i <= n; ++i){
    for(j = 1; j <= n; ++j){
      pu = find(i);
      pv = find(j);
      if(pu != pv && col[i] != col[j]){
        printf("%d %d 0\n", i, j);
        p[pu] = pv;
      }
    }
  }
  return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int pu, pv, w, mn, i, j, cnt;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(w){
      if(col[i]) bl.push(edge(i, w));
      else wh.push(edge(i, w));
    }
  }

  cnt = n - 1;
  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
    --cnt;
  }

  pu = find(n);
  for(i = 1; i < n && cnt; ++i){
    if(col[i] != col[n]){
      pv = find(i);
      if(pu != pv){
        p[pu] = pv;
        printf("%d %d 0\n", i, n);
        --cnt;
      } else {
        for(j = 1; j < n && cnt; ++j){
          if(col[i] != col[j] && pv != find(j)){
            p[pv] = find(j);
            printf("%d %d 0\n", i, j);
            --cnt;
          }
        }
      }
    }
  }
  return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int w, mn, i, j, cnt;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(w){
      if(col[i]) bl.push(edge(i, w));
      else wh.push(edge(i, w));
    }
  }

  cnt = n - 1;
  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
    --cnt;
  }

  for(i = 1; i < n && cnt; ++i){
    if(col[i] != col[n]){
      if(find(i) != find(n)){
        p[find(i)] = find(n);
        printf("%d %d 0\n", i, n);
        --cnt;
      } else {
        for(j = 1; j < n && cnt; ++j){
          if(col[i] != col[j] && find(i) != find(j)){
            p[find(i)] = find(j);
            printf("%d %d 0\n", i, j);
            --cnt;
          }
        }
      }
    }
  }
  return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int pu, pv, w, mn, i, j, cnt;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(w){
      if(col[i]) bl.push(edge(i, w));
      else wh.push(edge(i, w));
    }
  }

  cnt = n - 1;
  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
    --cnt;
  }

  pu = find(n);
  for(i = 1; i < n && cnt; ++i){
    if(col[i] != col[n]){
      pv = find(i);
      if(pu != pv){
        p[pv] = pu;
        printf("%d %d 0\n", i, n);
        --cnt;
      } else {
        for(j = 1; j < n && cnt; ++j){
          if(col[i] != col[j] && pv != find(j)){
            p[pv] = find(j);
            printf("%d %d 0\n", i, j);
            --cnt;
          }
        }
      }
    }
  }
  return 0;
}


#include <climits>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <numeric>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <list>
#include <bitset>
using namespace std;

#define out(x) cout<< x<< endl

struct edge{
  int nd, w;

  edge() {}
  edge(int a, int b) : nd(a), w(b) {}

  bool operator<(const edge &cmp) const{
    if(w == cmp.w) return nd > cmp.nd;
    return w > cmp.w;
  }
};

int n, p[100005], col[100005];

int find(int x){
  if(x == p[x]) return x;
  return p[x] = find(p[x]);
}

int main(){
//  freopen("d.in",  "r", stdin);
//  freopen("d.out", "w", stdout);

  int pu, pv, w, mn, i, j;
  edge nw, nb;
  priority_queue<edge> wh, bl;

  scanf("%d", &n);
  for(i = 1; i <= n; ++i){
    scanf("%d%d", &col[i], &w);
    p[i] = i;

    if(col[i]) bl.push(edge(i, w));
    else wh.push(edge(i, w));
  }

  while(!(wh.empty() || bl.empty())){
    nw = wh.top();
    nb = bl.top();
    wh.pop(), bl.pop();

    mn = min(nw.w, nb.w);
    printf("%d %d %d\n", nw.nd, nb.nd, mn);

    if(nw.w - mn) wh.push(edge(nw.nd, nw.w - mn));
    if(nb.w - mn) bl.push(edge(nb.nd, nb.w - mn));

    p[find(nw.nd)] = find(nb.nd);
  }

  pu = find(n);
  for(i = 1; i < n; ++i){
    pv = find(i);
    if(pu != pv && col[i] != col[n]){
      printf("%d %d 0\n", i, n);
    }
  }
  return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005

using namespace std;

struct Edge {
    int x, y, val;

    void setValue(int x, int y, int val) {
        this->x = x;
        this->y = y;
        this->val = val;
    }
};

struct Vetex {
    int id, sum, color;
};

Vetex white[MAXN], black[MAXN];
Edge edges[MAXN];
int n;

bool cmp(Vetex a, Vetex b) {
    return a.sum < b.sum;
}

int main() {
    scanf("%d", &n);

    int cntEdge = 0;
    int cntWhite = 0;
    int cntBlack = 0;
    for(int i = 0; i < n; i++) {
        Vetex temp;
        temp.id = i + 1;
        scanf("%d%d", &temp.color, &temp.sum);
        if(temp.color == 0) {
            white[cntWhite++] = temp;
        } else {
            black[cntBlack++] = temp;
        }
    }
    sort(white, white + cntWhite, cmp);
    sort(black, black + cntBlack, cmp);

    int pWhite = 0;
    int pBlack = 0;
    /*
    while(white[pWhite].sum == 0 && pWhite < cntWhite) {
        edges[cntEdge++].setValue(white[pWhite].id, black[pBlack].id, 0);
        pWhite++;
    }
    if(pWhite > 0) {
        pBlack++;
    }
    while(black[pBlack].sum == 0 && pWhite < cntWhite && pBlack < cntBlack) {
        edges[cntEdge++].setValue(black[pBlack].id, white[pWhite].id, 0);
        pBlack++;
    }
    */
    Vetex cur = white[pWhite++];
    while(pWhite < cntWhite || pBlack < cntBlack) {
        Vetex t;
        if(cur.color == 0) {
            if(pBlack >= cntBlack) break;
            t = black[pBlack++];
        } else {
            if(pWhite >= cntWhite) break;
            t = white[pWhite++];
        }
        if(t.sum < cur.sum) {
            cur.sum -= t.sum;
            edges[cntEdge++].setValue(cur.id, t.id, t.sum);
        } else {
            t.sum -= cur.sum;
            edges[cntEdge++].setValue(cur.id, t.id, cur.sum);
            if((cur.color == 0 && pWhite < cntWhite) || (cur.color == 1 && pBlack < cntBlack)) {
                cur = t;
            }
        }
    }
    for(int i = 0; i < cntEdge; i++) {
        printf("%d %d %d\n", edges[i].x, edges[i].y, edges[i].val);
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005

using namespace std;

struct Edge {
    int x, y, val;

    void setValue(int x, int y, int val) {
        this->x = x;
        this->y = y;
        this->val = val;
    }
};

struct Vetex {
    int id, sum, color;
};

Vetex white[MAXN], black[MAXN];
Edge edges[MAXN];
int n;

bool cmp(Vetex a, Vetex b) {
    return a.sum < b.sum;
}

int main() {
    scanf("%d", &n);

    int cntEdge = 0;
    int cntWhite = 0;
    int cntBlack = 0;
    for(int i = 0; i < n; i++) {
        Vetex temp;
        temp.id = i + 1;
        scanf("%d%d", &temp.color, &temp.sum);
        if(temp.color == 0) {
            white[cntWhite++] = temp;
        } else {
            black[cntBlack++] = temp;
        }
    }
    sort(white, white + cntWhite, cmp);
    sort(black, black + cntBlack, cmp);

    int pWhite = 0;
    int pBlack = 0;
    Vetex cur;
    if(white[pWhite].sum == 0) {
        cur = white[pWhite++];
    } else {
        cur = black[pBlack++];
    }
    while(cur.sum == 0) {
        Vetex t;
        if(cur.color == 0) {
            if(pBlack >= cntBlack) break;
            t = black[pBlack++];
        } else {
            if(pWhite >= cntWhite) break;
            t = white[pWhite++];
        }
        edges[cntEdge++].setValue(cur.id, t.id, 0);
        cur = t;
    }
    while(pWhite < cntWhite || pBlack < cntBlack) {
        Vetex t;
        if(cur.color == 0) {
            if(pBlack >= cntBlack) break;
            t = black[pBlack++];
        } else {
            if(pWhite >= cntWhite) break;
            t = white[pWhite++];
        }
        if(t.sum <= cur.sum) {
            cur.sum -= t.sum;
            edges[cntEdge++].setValue(cur.id, t.id, t.sum);
        } else {
            t.sum -= cur.sum;
            edges[cntEdge++].setValue(cur.id, t.id, cur.sum);
            cur = t;
        }
    }
    for(int i = 0; i < cntEdge; i++) {
        printf("%d %d %d\n", edges[i].x, edges[i].y, edges[i].val);
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 100005

using namespace std;

struct Edge {
    int x, y, val;

    void setValue(int x, int y, int val) {
        this->x = x;
        this->y = y;
        this->val = val;
    }
};

struct Vetex {
    int id, sum, color;
};

queue<Vetex> white, black;
Edge edges[MAXN];
int n;

int main() {
    scanf("%d", &n);
    for(int i = 0; i < n; i++) {
        Vetex temp;
        temp.id = i + 1;
        scanf("%d%d", &temp.color, &temp.sum);
        if(temp.color == 0) {
            white.push(temp);
        } else {
            black.push(temp);
        }
    }
    int cnt = 0;
    while(!white.empty() || !black.empty()) {
        Vetex cur = white.front();
        white.pop();
        while(cur.sum >= 0) {
            Vetex t;
            if(cur.color == 0) {
                if(black.empty()) break;
                t = black.front();
                black.pop();
            } else {
                if(white.empty()) break;
                t = white.front();
                white.pop();
            }
            if(t.sum <= cur.sum) {
                cur.sum -= t.sum;
                edges[cnt++].setValue(cur.id, t.id, t.sum);
            } else {
                t.sum -= cur.sum;
                edges[cnt++].setValue(cur.id, t.id, cur.sum);
                cur = t;
            }
        }
    }
    for(int i = 0; i < cnt; i++) {
        printf("%d %d %d\n", edges[i].x, edges[i].y, edges[i].val);
    }
    return 0;
}


#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005

using namespace std;

struct Edge {
    int x, y, val;

    void setValue(int x, int y, int val) {
        this->x = x;
        this->y = y;
        this->val = val;
    }
};

struct Vetex {
    int id, sum, color;
};

Vetex white[MAXN], black[MAXN];
Edge edges[MAXN];
int n;

bool cmp(Vetex a, Vetex b) {
    return a.sum < b.sum;
}

int main() {
    scanf("%d", &n);

    int cntEdge = 0;
    int cntWhite = 0;
    int cntBlack = 0;
    for(int i = 0; i < n; i++) {
        Vetex temp;
        temp.id = i + 1;
        scanf("%d%d", &temp.color, &temp.sum);
        if(temp.color == 0) {
            white[cntWhite++] = temp;
        } else {
            black[cntBlack++] = temp;
        }
    }
    sort(white, white + cntWhite, cmp);
    sort(black, black + cntBlack, cmp);

    int pWhite = 0;
    int pBlack = 0;
    while(white[pWhite].sum == 0 && pWhite < cntWhite) {
        edges[cntEdge++].setValue(white[pWhite].id, black[pBlack].id, 0);
        pWhite++;
    }
    if(pWhite > 0) {
        pBlack++;
    }
    while(black[pBlack].sum == 0 && pWhite < cntWhite && pBlack < cntBlack) {
        edges[cntEdge++].setValue(black[pBlack].id, white[pWhite].id, 0);
        pBlack++;
    }

    Vetex cur = white[pWhite];
    while(pWhite < cntWhite || pBlack < cntBlack) {
        Vetex t;
        if(cur.color == 0) {
            if(pBlack >= cntBlack) break;
            t = black[pBlack++];
        } else {
            if(pWhite >= cntWhite) break;
            t = white[pWhite++];
        }
        if(t.sum <= cur.sum) {
            cur.sum -= t.sum;
            edges[cntEdge++].setValue(cur.id, t.id, t.sum);
        } else {
            t.sum -= cur.sum;
            edges[cntEdge++].setValue(cur.id, t.id, cur.sum);
            cur = t;
        }
    }
    for(int i = 0; i < cntEdge; i++) {
        printf("%d %d %d\n", edges[i].x, edges[i].y, edges[i].val);
    }
    return 0;
}


#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <climits>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
#define  LL long long
#define  pb push_back
#define  inst insert
#define  mp make_pair
#define  lson(idx) (idx << 1)
#define  rson(idx) ((idx << 1) ^ 1)
#define  sz(x) ((int)(x).size())
#define  ForEach(i,c) for(__typeof((c).begin()) i = (c).begin();i != (c).end();i++)
using namespace std;

inline bool cmp(pair<int, int> a, pair<int, int> b){
	return a.second < b.second;
}
const int N = 100010;
int check[N];

int Find(int x){
	return x != check[x] ? check[x] = Find(check[x]) : check[x];
}

void Union(int a, int b){
	int fa = Find(a);
	int fb = Find(b);
	if(fa != fb)
		check[fa] = fb;
}

int main(){
	int n, i, col, t;
	vector<pair<int, int> > b, w;
	cin >> n;
	for(i = 1;i <= n;i++){
		check[i] = i;
		cin >> col >> t;
		if(col)
			b.pb(mp(i, t));
		else
			w.pb(mp(i, t));
	}
	sort(w.begin(), w.end(), cmp);
	sort(b.begin(), b.end(), cmp);
	int j = sz(w) - 1;
	for(i = 0;i < sz(b);i++){
		int w1 = b[i].second;
		for(;j >= 0 && w1 > 0;){
			int w2 = w[j].second;
			int c = min(w1, w2);
			w1 -= c;
			w2 -= c;
			printf("%d %d %d\n", b[i].first, w[j].first, c);
			Union(b[i].first, w[j].first);
			if(w2 <= 0)
				j--;
		}
	}
	for(i = 0;i < sz(b);i++){
		int fb = Find(b[i].first);
		int fw = Find(w[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", b[i].first, w[0].first, 0);
		}
	}
	for(i = 0;i < sz(w);i++){
		int fw = Find(w[i].first);
		int fb = Find(b[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", w[i].first, b[0].first, 0);
		}
	}
	return 0;
}


#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <climits>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
#define  LL long long
#define  pb push_back
#define  inst insert
#define  mp make_pair
#define  lson(idx) (idx << 1)
#define  rson(idx) ((idx << 1) ^ 1)
#define  sz(x) ((int)(x).size())
#define  ForEach(i,c) for(__typeof((c).begin()) i = (c).begin();i != (c).end();i++)
using namespace std;

inline bool cmp(pair<int, int> a, pair<int, int> b){
	return a.second < b.second;
}

int main(){
	int n, i, col, t;
	vector<pair<int, int> > b, w;
	cin >> n;
	for(i = 1;i <= n;i++){
		cin >> col >> t;
		if(col)
			b.pb(mp(i, t));
		else
			w.pb(mp(i, t));
	}
	sort(w.begin(), w.end(), cmp);
	sort(b.begin(), b.end(), cmp);
	for(int j = 0, i = 0;i < sz(b);i++)
		for(;j < sz(w) && b[i].second > 0;){
			int c = min(b[i].second, w[j].second);
			b[i].second -= c;
			w[j].second -= c;
			printf("%d %d %d\n", b[i].first, w[j].first, c);
			if(w[j].second <= 0)
				j++;
		}
	return 0;
}


#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <climits>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
#define  LL long long
#define  pb push_back
#define  inst insert
#define  mp make_pair
#define  lson(idx) (idx << 1)
#define  rson(idx) ((idx << 1) ^ 1)
#define  sz(x) ((int)(x).size())
#define  ForEach(i,c) for(__typeof((c).begin()) i = (c).begin();i != (c).end();i++)
using namespace std;

inline bool cmp(pair<int, int> a, pair<int, int> b){
	return a.second < b.second;
}
const int N = 100010;
int check[N];

int Find(int x){
	return x != check[x] ? check[x] = Find(check[x]) : check[x];
}

void Union(int a, int b){
	int fa = Find(a);
	int fb = Find(b);
	if(fa != fb)
		check[fa] = fb;
}

int main(){
	int n, i, col, t;
	vector<pair<int, int> > b, w;
	cin >> n;
	for(i = 1;i <= n;i++){
		check[i] = i;
		cin >> col >> t;
		if(col)
			b.pb(mp(i, t));
		else
			w.pb(mp(i, t));
	}
	sort(w.begin(), w.end(), cmp);
	sort(b.begin(), b.end(), cmp);
	int j = 0;
	for(i = 0;i < sz(b);i++){
		int w1 = b[i].second;
		for(;j < sz(w) && w1 > 0;){
			int w2 = w[j].second;
			int c = min(w1, w2);
			w1 -= c;
			w2 -= c;
			printf("%d %d %d\n", b[i].first, w[j].first, c);
			Union(b[i].first, w[j].first);
			if(w2 <= 0)
				j++;
		}
	}
	for(i = 0;i < sz(b);i++){
		int fb = Find(b[i].first);
		int fw = Find(w[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", b[i].first, w[0].first, 0);
		}
	}
	for(i = 0;i < sz(w);i++){
		int fw = Find(w[i].first);
		int fb = Find(b[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", w[i].first, b[0].first, 0);
		}
	}
	return 0;
}


#include <set>
#include <map>
#include <cmath>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <bitset>
#include <cstdio>
#include <climits>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
#define  LL long long
#define  pb push_back
#define  inst insert
#define  mp make_pair
#define  lson(idx) (idx << 1)
#define  rson(idx) ((idx << 1) ^ 1)
#define  sz(x) ((int)(x).size())
#define  ForEach(i,c) for(__typeof((c).begin()) i = (c).begin();i != (c).end();i++)
using namespace std;

inline bool cmp(pair<int, int> a, pair<int, int> b){
	return a.second < b.second;
}
const int N = 100010;
int check[N];

int Find(int x){
	return x != check[x] ? check[x] = Find(check[x]) : check[x];
}

void Union(int a, int b){
	int fa = Find(a);
	int fb = Find(b);
	if(fa != fb)
		check[fa] = fb;
}

int main(){
	int n, i, col, t;
	vector<pair<int, int> > b, w;
	cin >> n;
	for(i = 1;i <= n;i++){
		check[i] = i;
		cin >> col >> t;
		if(col)
			b.pb(mp(i, t));
		else
			w.pb(mp(i, t));
	}
	sort(w.begin(), w.end(), cmp);
	sort(b.begin(), b.end(), cmp);
	for(int j = 0, i = 0;i < sz(b);i++)
		for(;j < sz(w) && b[i].second > 0;){
			int c = min(b[i].second, w[j].second);
			b[i].second -= c;
			w[j].second -= c;
			printf("%d %d %d\n", b[i].first, w[j].first, c);
			Union(b[i].first, w[j].first);
			if(w[j].second <= 0)
				j++;
		}

	for(i = 0;i < sz(b);i++){
		int fb = Find(b[i].first);
		int fw = Find(w[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", b[i].first, w[0].first, 0);
		}
	}
	for(i = 0;i < sz(w);i++){
		int fw = Find(w[i].first);
		int fb = Find(b[0].first);
		if(fb != fw){
			Union(fb, fw);
			printf("%d %d %d\n", w[i].first, b[0].first, 0);
		}
	}
	return 0;
}


#include <iostream>
#include <fstream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <climits>
#include <ctime>
#define pb push_back
#define fi first
#define sc second
#define inf	1000000000
#define dbg(x) cerr<<#x<<":"<<x<<endl
#define N 100005
#define MP make_pair
#define orta ((a+b)/2)
using namespace std;
typedef long long int lint;
typedef pair<int,int> ii;
int n;
ii d[N],cev[N];
set <ii> st1,st2;
int main()
{
	scanf("%d",&n);
	for (int i = 1; i <= n; i++)
	{
		int o1;
		scanf("%d %d",&o1,&d[i].fi);
		d[i].sc=i;
		if(o1==1)
			st1.insert(d[i]);
		else
			st2.insert(d[i]);
	}
	while(!st1.empty() && !st2.empty())
	{
		set<ii>::iterator t1=st1.begin(),t2=st2.begin();
		if(t1->fi < t2->fi)
		{
			ii tut;
			tut.fi=t2->fi-t1->fi;
			tut.sc=t2->sc;
			cev[t1->sc].fi=t2->sc;
			cev[t1->sc].sc=t1->fi;
			st1.erase (t1);
			st2.erase (t2);
			st2.insert(tut);
		}
		else
		{
			ii tut;
			tut.fi=t1->fi-t2->fi;
			tut.sc=t1->sc;
			cev[t2->sc].fi=t1->sc;
			cev[t2->sc].sc=t2->fi;
			st1.erase (t1);
			st2.erase (t2);
			st1.insert(tut);
		}
	}
	for (int i = 1; i <= n; i++)
		if(cev[i].fi!=0)
			printf("%d %d %d\n",i,cev[i].fi,cev[i].sc);

}


#include <iostream>
#include <fstream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <climits>
#include <ctime>
#define pb push_back
#define fi first
#define sc second
#define inf	1000000000
#define dbg(x) cerr<<#x<<":"<<x<<endl
#define N 100005
#define MP make_pair
#define orta ((a+b)/2)
using namespace std;
typedef long long int lint;
typedef pair<int,int> ii;
int n;
ii d[N],cev[N];
set <ii> st1,st2;
int main()
{
	scanf("%d",&n);
	for (int i = 1; i <= n; i++)
	{
		int o1;
		scanf("%d %d",&o1,&d[i].fi);
		d[i].sc=i;
		if(o1==1)
			st1.insert(d[i]);
		else
			st2.insert(d[i]);
	}
	while(!st1.empty() && !st2.empty())
	{
		set<ii>::iterator t1=st1.begin(),t2=st2.begin();
		if(t1->fi < t2->fi)
		{
			ii tut;
			tut.fi=t2->fi-t1->fi;
			tut.sc=t2->sc;
			cev[t1->sc].fi=t2->sc;
			cev[t1->sc].sc=t1->fi;
			st1.erase (t1);
			st2.erase (t2);
			st2.insert(tut);
		}
		else
		{
			ii tut;
			tut.fi=t1->fi-t2->fi;
			tut.sc=t1->sc;
			cev[t2->sc].fi=t1->sc;
			cev[t2->sc].sc=t2->fi;
			st1.erase (t1);
			st2.erase (t2);
			st1.insert(tut);
		}
	}
	for (int i = 1; i <= n; i++)
		if(cev[i].sc!=0)
			printf("%d %d %d\n",i,cev[i].fi,cev[i].sc);

}


#include <iostream>
#include <fstream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <climits>
#include <ctime>
#define pb push_back
#define fi first
#define sc second
#define inf	1000000000
#define dbg(x) cerr<<#x<<":"<<x<<endl
#define N 100005
#define MP make_pair
#define orta ((a+b)/2)
using namespace std;
typedef long long int lint;
typedef pair<int,int> ii;
int n;
ii d[N],cev[N];
set <ii> st1,st2;
int main()
{
	scanf("%d",&n);
	for (int i = 1; i <= n; i++)
	{
		int o1;
		scanf("%d %d",&o1,&d[i].fi);
		d[i].sc=i;
		if(o1==1)
			st1.insert(d[i]);
		else
			st2.insert(d[i]);
	}
	while(!st1.empty() && !st2.empty())
	{
		set<ii>::iterator t1=st1.begin(),t2=st2.begin();
		if((t1->fi < t2->fi) || ((t1->fi == t2->fi) && (st1.size())>(st2.size())))
		{
			ii tut;
			tut.fi=t2->fi-t1->fi;
			tut.sc=t2->sc;
			cev[t1->sc].fi=t2->sc;
			cev[t1->sc].sc=t1->fi;
			st1.erase (t1);
			st2.erase (t2);
			st2.insert(tut);
		}
		else
		{
			ii tut;
			tut.fi=t1->fi-t2->fi;
			tut.sc=t1->sc;
			cev[t2->sc].fi=t1->sc;
			cev[t2->sc].sc=t2->fi;
			st1.erase (t1);
			st2.erase (t2);
			st1.insert(tut);
		}
	}
	for (int i = 1; i <= n; i++)
		if(cev[i].fi!=0)
			printf("%d %d %d\n",i,cev[i].fi,cev[i].sc);

}


#include <iostream>
#include <fstream>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <climits>
#include <ctime>
#define pb push_back
#define fi first
#define sc second
#define inf	1000000000
#define dbg(x) cerr<<#x<<":"<<x<<endl
#define N 100005
#define MP make_pair
#define orta ((a+b)/2)
using namespace std;
typedef long long int lint;
typedef pair<int,int> ii;
int n;
ii d[N],cev[N];
set <ii> st1,st2;
int main()
{
	scanf("%d",&n);
	for (int i = 1; i <= n; i++)
	{
		int o1;
		scanf("%d %d",&o1,&d[i].fi);
		d[i].sc=i;
		if(o1==1)
			st1.insert(d[i]);
		else
			st2.insert(d[i]);
	}
	while(!st1.empty() && !st2.empty())
	{
		set<ii>::iterator t1=st1.begin(),t2=st2.begin();
		if((t1->fi < t2->fi) || ((t1->fi == t2->fi) && (st1.size())<(st2.size())))
		{
			ii tut;
			tut.fi=t2->fi-t1->fi;
			tut.sc=t2->sc;
			cev[t1->sc].fi=t2->sc;
			cev[t1->sc].sc=t1->fi;
			st1.erase (t1);
			st2.erase (t2);
			st2.insert(tut);
		}
		else
		{
			ii tut;
			tut.fi=t1->fi-t2->fi;
			tut.sc=t1->sc;
			cev[t2->sc].fi=t1->sc;
			cev[t2->sc].sc=t2->fi;
			st1.erase (t1);
			st2.erase (t2);
			st1.insert(tut);
		}
	}
	for (int i = 1; i <= n; i++)
		if(cev[i].fi!=0)
			printf("%d %d %d\n",i,cev[i].fi,cev[i].sc);

}


#include <bits/stdc++.h>

using namespace std;

#define ll 		long long
#define mp 		make_pair
#define sz(v) 	(int)v.size()
#define pb    	push_back
#define b_p(n)		__builtin_popcount(n)
#define s second
#define f first
#define mxN 1000009
bool clr[mxN], vis[mxN];
vector<vector<int> > adj(100);

void dfs(int pre, int node, pair<int, int> &nodes) {
	if (clr[node])
		nodes.f = node;
	else
		nodes.s = node;
	if (vis[node])
		return;
	vis[node] = 1;
	for (int i = 0; i < sz(adj[node]); i++)
		dfs(node, adj[node][i], nodes);
	return;
}
int main() {
	int n;
	scanf("%d", &n);
	adj.resize(n + 1);
	vector<pair<int, int> > white, black;
	for (int i = 0; i < n; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (x)
			white.pb(mp(i + 1, y));
		else
			black.pb(mp(i + 1, y));
		clr[i + 1] = x;
	}
	int ctr = 0;
	for (int p1 = 0, p2 = 0; p1 < sz(white) && p2 < sz(black);) {
		int mn = min(white[p1].s, black[p2].s);
		white[p1].s -= mn;
		black[p2].s -= mn;
		printf("%d %d %d\n", white[p1].f, black[p2].f, mn);
		adj[white[p1].f].pb(black[p2].f);
		adj[black[p2].f].pb(white[p1].f);
		ctr++;
		if (white[p1].s == 0)
			p1++;
		if (black[p2].s == 0)
			p2++;
	}
	vector<pair<int, int> > connected;
	pair<int, int> whitenode, blacknode;
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			pair<int, int> p = mp(0, 0);
			dfs(0, i, p);
			connected.pb(p);
			if (p.f != 0)
				whitenode = mp(sz(connected) - 1, p.f);
			if (p.s != 0)
				blacknode = mp(sz(connected) - 1, p.s);
		}
	}
	for (int i = 0; i < sz(connected); i++) {
		if (connected[i].s != 0 && whitenode.f != i)
			printf("%d %d %d\n", whitenode.s, connected[i].s, 0);
		else if (blacknode.f != i)
			printf("%d %d %d\n", blacknode.s, connected[i].f, 0);
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll 		long long
#define mp 		make_pair
#define sz(v) 	(int)v.size()
#define pb    	push_back
#define b_p(n)		__builtin_popcount(n)
#define s second
#define f first
#define mxN 1000009
bool clr[mxN], vis[mxN];
vector<vector<int> > adj(100);

void dfs(int pre, int node, pair<int, int> &nodes) {
	if (clr[node])
		nodes.f = node;
	else
		nodes.s = node;
	if (vis[node])
		return;
	vis[node] = 1;
	for (int i = 0; i < sz(adj[node]); i++)
		dfs(node, adj[node][i], nodes);
	return;
}
int main() {
	int n;
	scanf("%d", &n);
	adj.resize(n + 1);
	vector<pair<int, int> > white, black;
	for (int i = 0; i < n; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (x)
			white.pb(mp(i + 1, y));
		else
			black.pb(mp(i + 1, y));
		clr[i + 1] = x;
	}
	int ctr = 0;
	for (int p1 = 0, p2 = 0; p1 < sz(white) && p2 < sz(black);) {
		int mn = min(white[p1].s, black[p2].s);
		white[p1].s -= mn;
		black[p2].s -= mn;
		printf("%d %d %d\n", white[p1].f, black[p2].f, mn);
		adj[white[p1].f].pb(black[p2].f);
		adj[black[p2].f].pb(white[p1].f);
		ctr++;
		if (white[p1].s == 0)
			p1++;
		if (black[p2].s == 0)
			p2++;
	}
	vector<pair<int, int> > connected;
	pair<int, int> whitenode=mp(-1,-1), blacknode=mp(-1,-1);
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			pair<int, int> p = mp(0, 0);
			dfs(0, i, p);
			connected.pb(p);
			if (p.f != 0)
				whitenode = mp(sz(connected) - 1, p.f);
			if (p.s != 0)
				blacknode = mp(sz(connected) - 1, p.s);
		}
	}
	if(blacknode.s !=whitenode.s && ctr != n-1)
		printf("%d %d %d\n", whitenode.s, blacknode.s, 0);

	for (int i = 0; i < sz(connected); i++) {
		if(blacknode.f ==i || whitenode.f==i)
			continue;
		if (connected[i].s != 0)
			printf("%d %d %d\n", whitenode.s, connected[i].s, 0);
		else
			printf("%d %d %d\n", blacknode.s, connected[i].f, 0);
	}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll 		long long
#define mp 		make_pair
#define sz(v) 	(int)v.size()
#define pb    	push_back
#define b_p(n)		__builtin_popcount(n)
#define s second
#define f first
#define mxN 1000009
bool clr[mxN], vis[mxN];
vector<vector<int> > adj(100);

void dfs(int pre, int node, pair<int, int> &nodes) {
	if (clr[node])
		nodes.f = node;
	else
		nodes.s = node;
	if (vis[node])
		return;
	vis[node] = 1;
	for (int i = 0; i < sz(adj[node]); i++)
		dfs(node, adj[node][i], nodes);
	return;
}
int main() {
	int n;
	scanf("%d", &n);
	adj.resize(n + 1);
	vector<pair<int, int> > white, black;
	for (int i = 0; i < n; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (x)
			white.pb(mp(i + 1, y));
		else
			black.pb(mp(i + 1, y));
		clr[i + 1] = x;
	}
	int ctr = 0;
	for (int p1 = 0, p2 = 0; p1 < sz(white) && p2 < sz(black);) {
		int mn = min(white[p1].s, black[p2].s);
		white[p1].s -= mn;
		black[p2].s -= mn;
		printf("%d %d %d\n", white[p1].f, black[p2].f, mn);
		adj[white[p1].f].pb(black[p2].f);
		adj[black[p2].f].pb(white[p1].f);
		ctr++;
		if (white[p1].s == 0)
			p1++;
		if (black[p2].s == 0)
			p2++;
	}
	vector<pair<int, int> > connected;
	bool taken[mxN];
	memset(taken, 0, sizeof(taken));
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			pair<int, int> p = mp(0, 0);
			dfs(0, i, p);
			connected.pb(p);
		}
	}
	for (int i = 0; i < sz(connected); i++) {
		if (connected[i].f != 0) {
			for (int j = 0; j < sz(connected); j++) {
				if (connected[j].s != 0 && i!=j) {
					printf("%d %d %d\n", connected[i].f, connected[j].s, 0);
				}
			}
			taken[i] = 1;
			break;
		}
	}
	for (int i = 0; i < sz(connected); i++)
		if (connected[i].s != 0){
			for (int j = 0; j < sz(connected); j++)
				if (!taken[j] && connected[j].f != 0 && i!=j)
					printf("%d %d %d\n", connected[i].s, connected[j].f, 0);
			break;
		}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll 		long long
#define mp 		make_pair
#define sz(v) 	(int)v.size()
#define pb    	push_back
#define b_p(n)		__builtin_popcount(n)
#define s second
#define f first
#define mxN 1000009
bool clr[mxN], vis[mxN];
vector<vector<int> > adj(100);

void dfs(int pre, int node, pair<int, int> &nodes) {
	if (clr[node])
		nodes.f = node;
	else
		nodes.s = node;
	if (vis[node])
		return;
	vis[node] = 1;
	for (int i = 0; i < sz(adj[node]); i++)
		dfs(node, adj[node][i], nodes);
	return;
}
int main() {
	int n;
	scanf("%d", &n);
	adj.resize(n + 1);
	vector<pair<int, int> > white, black;
	for (int i = 0; i < n; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (x)
			white.pb(mp(i + 1, y));
		else
			black.pb(mp(i + 1, y));
		clr[i + 1] = x;
	}
	int ctr = 0;
	for (int p1 = 0, p2 = 0; p1 < sz(white) && p2 < sz(black);) {
		int mn = min(white[p1].s, black[p2].s);
		white[p1].s -= mn;
		black[p2].s -= mn;
		printf("%d %d %d\n", white[p1].f, black[p2].f, mn);
		adj[white[p1].f].pb(black[p2].f);
		adj[black[p2].f].pb(white[p1].f);
		ctr++;
		if (white[p1].s == 0)
			p1++;
		if (black[p2].s == 0)
			p2++;
	}
	vector<pair<int, int> > connected;

	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			pair<int, int> p = mp(0, 0);
			dfs(0, i, p);
			connected.pb(p);
		}
	}
	for (int i = 0; i < sz(connected); i++) {
		if (connected[i].f != 0) {
			for (int j = 0; j < sz(connected); j++) {
				if (connected[j].s != 0 && i!=j) {
					connected[j].f=0;
					printf("%d %d %d\n", connected[i].f, connected[j].s, 0);
				}
			}
			connected[i].f=0;
			break;
		}
	}
	for (int i = 0; i < sz(connected); i++)
		if (connected[i].s != 0){
			for (int j = 0; j < sz(connected); j++)
				if (connected[j].f != 0 && i!=j)
					printf("%d %d %d\n", connected[i].s, connected[j].f, 0);
			break;
		}
	return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define ll 		long long
#define mp 		make_pair
#define sz(v) 	(int)v.size()
#define pb    	push_back
#define b_p(n)		__builtin_popcount(n)
#define s second
#define f first
#define mxN 1000009
bool clr[mxN], vis[mxN];
vector<vector<int> > adj(100);

void dfs(int pre, int node, pair<int, int> &nodes) {
	if (clr[node])
		nodes.f = node;
	else
		nodes.s = node;
	if (vis[node])
		return;
	vis[node] = 1;
	for (int i = 0; i < sz(adj[node]); i++)
		dfs(node, adj[node][i], nodes);
	return;
}
int main() {
	int n;
	scanf("%d", &n);
	adj.resize(n + 1);
	vector<pair<int, int> > white, black;
	for (int i = 0; i < n; ++i) {
		int x, y;
		scanf("%d %d", &x, &y);
		if (x)
			white.pb(mp(i + 1, y));
		else
			black.pb(mp(i + 1, y));
		clr[i + 1] = x;
	}
	int ctr = 0;
	for (int p1 = 0, p2 = 0; p1 < sz(white) && p2 < sz(black);) {
		int mn = min(white[p1].s, black[p2].s);
		white[p1].s -= mn;
		black[p2].s -= mn;
		printf("%d %d %d\n", white[p1].f, black[p2].f, mn);
		adj[white[p1].f].pb(black[p2].f);
		adj[black[p2].f].pb(white[p1].f);
		ctr++;
		if (white[p1].s == 0)
			p1++;
		if (black[p2].s == 0)
			p2++;
	}
	vector<pair<int, int> > connected;
	pair<int, int> whitenode;
	for (int i = 1; i <= n; i++) {
		if (!vis[i]) {
			pair<int, int> p = mp(0, 0);
			dfs(0, i, p);
			connected.pb(p);
			if (p.f != 0)
				whitenode = mp(sz(connected) - 1, p.f);
		}
	}
	for (int i = 0; i < sz(connected); i++) {
		if (whitenode.f != i)
			printf("%d %d %d\n", whitenode.s, connected[i].s, 0);
	}
	return 0;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
bool operator < (const data &a1, const data &a2){
    if(a1.u == a2.u) return a1.v < a2.v;
    return a1.u < a2.u;
}
set<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
vector<T> one;
set<T> zero;
vector<int> z[8];
void handle(int, int);
void handlezero();
int in[8];
int main()
{
    int n;
    si(n);
    int w,type;
    FREP(n){
        si(type);si(w);
        in[type] = i;
        if(w == 0){
            z[type].pb(i);
            continue;
        }
        if(type == 0)
            zero.insert(T(w,i));
        else
            one.pb(T(w,i));
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    set<data> :: iterator it;
    for(it = ans.begin(); it!=ans.end(); it++){
        pis(it->u+1);pis(it->v+1);pi(it->w);
    }
    return 0;
}
void handlezero(){
    FREP(z[1].size()){
        if(in[0] > z[1][i])
            ans.insert(data(in[0], z[1][i], 0));
        else ans.insert(data(z[1][i], in[0], 0));
    }
    FREP(z[0].size()){
        if(in[1] > z[0][i])
            ans.insert(data(in[1], z[0][i], 0));
        else ans.insert(data(z[0][i], in[1], 0));
    }
    return;
}
set<T> pi;
void handle(int we, int I){
    set<T>:: iterator it = zero.begin(), it2;
    while(it!=zero.end()){
        int mini = min(we, it->w);
        if(I > it->in)
            ans.insert(data(I, it->in, mini));
        else ans.insert(data(it->in, I, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        it2 = it;
        it++;
        zero.erase(it2);
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
    pi.clear();
    return ;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
vector<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
bool operator == (const T &a1, const T &a2){
    return (a1.in == a2.in);
}
vector<T> one;
set<T> zero;
vector<int> z[2];
void handle(int, int);
void handlezero();
int in1,in0;
int main()
{
    int n;
    si(n);
    int w,type,in;
    FREP(n){
        si(type);si(w);
        if(w == 0){
            z[type].pb(i);
            (type == 0) ? (in0 = i) : (in1 = i);
            continue;
        }
        if(type == 0){
            zero.insert(T(w,i));
            in0 = i;
        }
        else{
            one.pb(T(w,i));
            in1 = i;
        }
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    FREP(ans.size()){
        pis(ans[i].u+1);pis(ans[i].v+1);pi(ans[i].w);
    }
    return 0;
}
void handlezero(){
        FREP(z[1].size()){
            ans.pb(data(in0, z[1][i], 0));
        }
        FREP(z[0].size()){
            ans.pb(data(in1, z[0][i], 0));
        }
}
void handle(int we, int I){
    set<T>:: iterator it;
    set<T> pi;
    for(it = zero.begin(); it!= zero.end(); it++){
        int mini = min(we, it->w);
        ans.pb(data(I, it->in, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        zero.erase(it);
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
vector<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
vector<T> one;
set<T> zero;
vector<int> z[2];
void handle(int, int);
void handlezero();
int in[2];
int in1[2];
int main()
{
    int n;
    si(n);
    int w,type;
    int zz;
    FREP(n){
        si(type);si(w);
        in[type] = i;
        if(w == 0){
            z[type].pb(i);
            continue;
        }
        if(type == 0){
            zero.insert(T(w,i));
            zz = i;
        }
        else
            one.pb(T(w,i));
    }
    if(one.size() > 0){
        in[1] = one[0].in;
    }
    if(zero.size() > 0){
        in[0] = zz;
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    FREP(ans.size()){
        pis(ans[i].u+1);pis(ans[i].v+1);pi(ans[i].w);
    }
    return 0;
}
#define rock(a,b) (a>b)?ii(a,b):ii(b,a)
void handlezero(){
    int mini = min(z[0].size(), z[1].size());
    set<ii> S;
    FREP(z[1].size()){
        S.insert(rock(z[1][i], in[0]));
    }
    FREP(z[0].size()){
        S.insert(rock(z[0][i], in[1]));
    }
    for(set<ii>::iterator it = S.begin(); it!=S.end();it++){
        ans.pb(data(it->first, it->second, 0));
    }
    return;
}
set<T> pi;
void handle(int we, int I){
    set<T>:: iterator it = zero.begin(), it2;
    while(it!=zero.end()){
        int mini = min(we, it->w);
        ans.pb(data(I, it->in, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        it2 = it;
        it++;
        zero.erase(it2);
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
    pi.clear();
    return ;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
vector<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
vector<T> one;
set<T> zero;
vector<int> z[8];
void handle(int, int);
void handlezero();
int in[8];
int main()
{
    int n;
    si(n);
    int w,type;
    FREP(n){
        si(type);si(w);
        in[type] = i;
        if(w == 0){
            z[type].pb(i);
            continue;
        }
        if(type == 0)
            zero.insert(T(w,i));
        else
            one.pb(T(w,i));
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    FREP(ans.size()){
        pis(ans[i].u+1);pis(ans[i].v+1);pi(ans[i].w);
    }
    return 0;
}
void handlezero(){
        FREP(z[1].size()){
            ans.pb(data(in[0], z[1][i], 0));
        }
        FREP(z[0].size()){
            ans.pb(data(in[1], z[0][i], 0));
        }
        return;
}
set<T> pi;
void handle(int we, int I){
    set<T>:: iterator it = zero.begin(), it2;
    while(it!=zero.end()){
        int mini = min(we, it->w);
        ans.pb(data(I, it->in, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        it2 = it;
        zero.erase(it2);
        it++;
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
    pi.clear();
    return ;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
bool operator < (const data &a1, const data &a2){
    if(a1.u == a2.v) return a1.v < a2.v;
    return a1.u < a2.u;
}
set<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
vector<T> one;
set<T> zero;
vector<int> z[8];
void handle(int, int);
void handlezero();
int in[8];
int main()
{
    int n;
    si(n);
    int w,type;
    FREP(n){
        si(type);si(w);
        in[type] = i;
        if(w == 0){
            z[type].pb(i);
            continue;
        }
        if(type == 0)
            zero.insert(T(w,i));
        else
            one.pb(T(w,i));
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    set<data> :: iterator it;
    for(it = ans.begin(); it!=ans.end(); it++){
        pis(it->u+1);pis(it->v+1);pi(it->w);
    }
    return 0;
}
void handlezero(){
    FREP(z[1].size()){
        if(in[0] > z[1][i])
            ans.insert(data(in[0], z[1][i], 0));
        else ans.insert(data(z[1][i], in[0], 0));
    }
    FREP(z[0].size()){
        if(in[1] > z[0][i])
            ans.insert(data(in[1], z[0][i], 0));
        else ans.insert(data(z[1][i], in[1], 0));
    }
    return;
}
set<T> pi;
void handle(int we, int I){
    set<T>:: iterator it = zero.begin(), it2;
    while(it!=zero.end()){
        int mini = min(we, it->w);
        if(I > it->in)
            ans.insert(data(I, it->in, mini));
        else ans.insert(data(it->in, I, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        it2 = it;
        it++;
        zero.erase(it2);
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
    pi.clear();
    return ;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 00:34:48 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007

struct data{
    int u,v,w;
    data(int U, int V, int W): w(W), u(U), v(V) {}
    data(){}
};
vector<data> ans;
struct T{
    int w, in;
    T(int W, int i) : w(W), in(i) {}
    T() {}
};
bool operator < (const T &a1, const T &a2){
    if(a1.w == a2.w) return a1.in < a2.in;
    return (a1.w < a2.w) ;

}
vector<T> one;
set<T> zero;
vector<int> z[8];
void handle(int, int);
void handlezero();
int in[8];
int main()
{
    int n;
    si(n);
    int w,type;
    FREP(n){
        si(type);si(w);
        in[type] = i;
        if(w == 0){
            z[type].pb(i);
            continue;
        }
        if(type == 0)
            zero.insert(T(w,i));
        else
            one.pb(T(w,i));
    }
    sort(one.begin(), one.end());
    FREP(one.size()){
        handle(one[i].w, one[i].in);
    }
    handlezero();
    FREP(ans.size()){
        pis(ans[i].u+1);pis(ans[i].v+1);pi(ans[i].w);
    }
    return 0;
}
void handlezero(){
        FREP(z[1].size()){
            ans.pb(data(in[0], z[1][i], 0));
        }
        FREP(z[0].size()){
            ans.pb(data(in[1], z[0][i], 0));
        }
        return;
}
set<T> pi;
void handle(int we, int I){
    set<T>:: iterator it;
    for(it = zero.begin(); it!= zero.end(); it++){
        int mini = min(we, it->w);
        ans.pb(data(I, it->in, mini));
        we -= mini;
        if(it->w - mini!=0){
            int a = it->w-mini, b = it->in;
            pi.insert(T(a, b));
        }
        zero.erase(it);
        if(we == 0) break;
    }
    for(it = pi.begin(); it!= pi.end();it++){
        zero.insert(T(it->w, it->in));
    }
    pi.clear();
    return ;
}


/*
Ashutosh Singla <ashu1461@gmail.com>
Algorithm:
#tags:
date: Sat Dec 14 02:10:53 IST 2013
*/

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<algorithm>
#include<climits>
using namespace std;
typedef vector<int> vi;
typedef pair<int,int> ii;
typedef long long LL;
#define FL(a) memset(a, 0, sizeof a);
#define fill(a,v,N) memset(a, v, sizeof(a[0])*N)
#define sz(a) int((a).size())
#define pb push_back
#define si(n) scanf("%d",&n)
#define sin(n) scanf("%d\n",&n) // for scanning strings ..
#define sill(n) scanf("%lld",&n)
#define pi(n) printf("%d\n",n);
#define pill(n) printf("%lld\n",n);
#define pis(n) printf("%d ",n);

#define all(c) (c).begin(),(c).end()
#define tr(c,i) for(typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define present(c,x) ((c).find(x) != (c).end())  // map and set find ..
#define cpresent(c,x) (find(all(c),x) != (c).end())  // stl find ..
#define FREP(b) for(int i=0;i<b;i++)
#define FREPr(b) for(int i=b-1;i>=0;i--)
#define REP(a,b,c) for(int a=b;a<c;a++)
#define REPr(a,b,c) for(int a=b;a>b;a--)
#define mp(a,b) make_pair(a,b);
typedef pair<int, int> ii;
#define MAX_S 100007
/*
struct data{
};
bool operator < (const data &a1, const data &a2){
}
*/
set<ii> S[2];
int main(){
    int N;
    si(N);
    int type, w;
    FREP(N){
        si(type);si(w);
        S[type].insert(ii(w,i+1));
    }
    int x=-1,y=-1;
    set<ii> :: iterator it1,it0;
    while(S[1].size()!= 0 && S[0].size()!= 0){
        it1 = S[1].begin(), it0 = S[0].begin();
        if(x==-1){
            x = it0->second;
        }
        if(y==-1){
            y = it1->second;
        }
    //    printf("Here for %d %d\n",it0->first, it1->first);
        if(it1->first > it0->first){
  //          printf("Removing from ... 0\n");
            ii d = ii(it1->first - it0->first, it1->second);
            printf("%d %d %d\n",it0->second, it1->second, it0->first);
            S[1].erase(it1);
            S[0].erase(it0);
            if(!S[0].empty())
                S[1].insert(d);
        }
        else{
//            printf("Removing from ... 1\n");
            ii d = ii(it0->first - it1->first, it0->second);
            printf("%d %d %d\n",it0->second, it1->second, it1->first);
            S[1].erase(it1);
            S[0].erase(it0);
             if(!S[1].empty())
                S[0].insert(d);
        }
    }
    for(it0 = S[0].begin(); it0 != S[0].end(); it0++){
        printf("%d %d %d\n",y,it0->second,0);
    }
    for(it1 = S[1].begin(); it1 != S[1].end(); it1++){
        printf("%d %d %d\n",y,it1->second,0);
    }
    return 0;
}