stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
// Peace Of SHIT

#include<bits/stdc++.h>

#define int long long

using namespace std;

typedef pair<int, int> pii;

const int maxn = 1e5 + 5;

int n, si[maxn];

int sum = 0;

vector<int> e[maxn];

pii d[maxn];



void impossible() {

	cout << -1;

	exit(0);

}



void dfs(int u, int x) {

	sum += x;

	for(int i = 0; i < e[u].size(); i++) {

		dfs(e[u][i], x + 1);

	}

}



int32_t main() {

	cin >> n;

	for(int i = 0; i < n; i++) {

		int a;

		cin >> a;

		d[i] = {a, i};

	}

	sort(d, d + n);

	reverse(d, d + n);

	

	vector <pii> k (d, d + n);

	

	for(int q = 0; q < n - 1; q++) {

		int leaf = d[q].second;

		int parD = d[q].first - (n - (2 * (si[leaf] + 1)));

		auto it = lower_bound(k.rbegin(), k.rend(), pii(parD, 0));

//		cout << "PAR : " <<it->first << " : " << parD << '\n';

		if(it -> first != parD) {

//			cerr << "AVALI\n";

			impossible();

		}

		int par = it -> second;

		si[par] += si[leaf] + 1;

		if((si[leaf] + 1) * 2 > n) {

//			cout << "DOVOMI\n";

			impossible();

		}

		//SEVOMI HAM MISHE D[I] ROOT OK E ?

		e[par].push_back(leaf);

	}

	int D = d[n - 1].second;

	dfs(D, 0);

	if(sum != d[n - 1].first)

		impossible();

	for(int i = 0; i < n; i++) {

		for(int j = 0; j < e[i].size(); j++)

			cout << i + 1 << " " << e[i][j] + 1 <<'\n';

	}

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.562886162876286x):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;



#define int ll

 

struct node{

	ll w;

	int y;

}a[100050];

 

struct node2{

	int t, nxt;

}edge[200050];

 

struct node3{int fr, f;};

 

int head[100050], cnt, n, siz[100050], anss;

 

void add(int u, int v){

	edge[++cnt] = (node2){v, head[u]};

	head[u] = cnt;

}

 

bool cmp(node a, node b){return a.w<b.w;}

 

int find(int u){

	for(int i = u-1; i >= 1; i--)if(a[i].w - a[u].w == 2*siz[a[u].y] - n) return a[i].y;

	return -1;

}

 

void print(int u, int fa){

	queue<node3> q;

	q.push((node3){u, fa});

	while(!q.empty()){

		u = q.front().fr;

		int ff = q.front().f;

		q.pop();

		for(int i = head[u]; i; i = edge[i].nxt){

			int v = edge[i].t;

			printf("%d %d\n", u, v);

			q.push((node3){v, u});

		}

	}

}



void test(int u, int fa, int dep){

	anss+=dep;

	for(int i = head[u]; i; i = edge[i].nxt){

		int v = edge[i].t;

		if(v == fa) continue;

		test(v, u, dep+1);

	}

}



main(){

	scanf("%d", &n);

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

		scanf("%lld", &a[i].w);

		a[i].y = i;

	}

	sort(a+1, a+n+1, cmp);

	int rt = a[1].y;

	for(int i = n; i >= 2; i--) {

		siz[a[i].y]++;

		int p = find(i);

		if(p == -1){

			printf("-1");

			return 0;

		}

		siz[p]+=siz[a[i].y];

		add(p, a[i].y);

	}

	test(rt, 0, 0);

	if(anss != a[1].w){

		printf("-1");

		return 0;

	}

	print(rt, 0);

}
// Slower C++ solution:
// Peace Of SHIT

#include<bits/stdc++.h>

#define int long long

using namespace std;

typedef pair<int, int> pii;

const int maxn = 1e5 + 5;

int n, si[maxn];

int sum = 0;

vector<int> e[maxn];

pii d[maxn];



void impossible() {

	cout << -1;

	exit(0);

}



void dfs(int u, int x) {

	sum += x;

	for(int i = 0; i < e[u].size(); i++) {

		dfs(e[u][i], x + 1);

	}

}



int32_t main() {

	scanf("%lld", &n);

	for(int i = 0; i < n; i++) {

		int a;

		scanf("%lld", &a);

		d[i] = {a, i};

	}

	sort(d, d + n);

	reverse(d, d + n);

	

	vector <pii> k (d, d + n);

	

	for(int q = 0; q < n - 1; q++) {

		int leaf = d[q].second;

		int parD = d[q].first - (n - (2 * (si[leaf] + 1)));

		auto it = lower_bound(k.rbegin(), k.rend(), pii(parD, 0));

//		cout << "PAR : " <<it->first << " : " << parD << '\n';

		if(it -> first != parD) {

//			cerr << "AVALI\n";

			impossible();

		}

		int par = it -> second;

		si[par] += si[leaf] + 1;

		if((si[leaf] + 1) * 2 > n) {

//			cout << "DOVOMI\n";

			impossible();

		}

		//SEVOMI HAM MISHE D[I] ROOT OK E ?

		e[par].push_back(leaf);

	}

	int D = d[n - 1].second;

	dfs(D, 0);

	if(sum != d[n - 1].first)

		impossible();

	for(int i = 0; i < n; i++) {

		for(int j = 0; j < e[i].size(); j++) {

			printf("%lld %lld\n", i + 1, e[i][j] + 1);

		}

	}

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5541255760286337x):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;



#define int ll

 

struct node{

	ll w;

	int y;

}a[100050];

 

struct node2{

	int t, nxt;

}edge[200050];

 

struct node3{int fr, f;};

 

int head[100050], cnt, n, siz[100050], anss;

 

void add(int u, int v){

	edge[++cnt] = (node2){v, head[u]};

	head[u] = cnt;

}

 

bool cmp(node a, node b){return a.w<b.w;}

 

int find(int u){

	for(int i = u-1; i >= 1; i--)if(a[i].w - a[u].w == 2*siz[a[u].y] - n) return a[i].y;

	return -1;

}

 

void print(int u, int fa){

	queue<node3> q;

	q.push((node3){u, fa});

	while(!q.empty()){

		u = q.front().fr;

		int ff = q.front().f;

		q.pop();

		for(int i = head[u]; i; i = edge[i].nxt){

			int v = edge[i].t;

			printf("%d %d\n", u, v);

			q.push((node3){v, u});

		}

	}

}



void test(int u, int fa, int dep){

	anss+=dep;

	for(int i = head[u]; i; i = edge[i].nxt){

		int v = edge[i].t;

		if(v == fa) continue;

		test(v, u, dep+1);

	}

}



main(){

	scanf("%d", &n);

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

		scanf("%lld", &a[i].w);

		a[i].y = i;

	}

	sort(a+1, a+n+1, cmp);

	int rt = a[1].y;

	for(int i = n; i >= 2; i--) {

		siz[a[i].y]++;

		int p = find(i);

		if(p == -1){

			printf("-1");

			return 0;

		}

		siz[p]+=siz[a[i].y];

		add(p, a[i].y);

	}

	test(rt, 0, 0);

	if(anss != a[1].w){

		printf("-1");

		return 0;

	}

	print(rt, 0);

}
// Slower C++ solution:
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N=100100;



map<LL,int> qaq;



void DSY(){

	puts("-1");

	exit(0);

}



int sz[N];



vector<int> es[N];

LL dd[N]={0};

LL d[N];

void dsy(int x,int fa=-1){

	for(vector<int>::iterator it=es[x].begin();it!=es[x].end();++it){

		if(*it==fa)continue;

		dsy(*it,x);

		dd[x]+=dd[*it]+sz[*it];

	}

}



vector<pair<int,int> > ess;

void ae(int u,int v){

	if(u>v)swap(u,v);

	ess.push_back(pair<int,int>(u,v));

	es[u].push_back(v);

	es[v].push_back(u);

}

void print(){

	sort(ess.begin(),ess.end());

	for(vector<pair<int,int> >::iterator it=ess.begin();it!=ess.end();++it){

		printf("%d %d\n",it->first,it->second);

	}

}



int main(){

	int n;

	scanf("%d",&n);

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

		scanf("%lld",&d[i]);

		qaq[d[i]]=i;

		sz[i]=1;

	}

	int cnt=n;

	for(map<LL,int>::reverse_iterator it=qaq.rbegin();it!=qaq.rend();++it){

		int x=it->second;

		LL ddd=it->first;

		if(sz[x]*2==n)DSY();

		LL nd=ddd+sz[x]-(n-sz[x]);

		if(cnt==1){

			dsy(x);

			if(dd[x]!=d[x])DSY();

			break;

		}

		if(!qaq.count(nd)){

			DSY();

		}else{

			int v=qaq[nd];

			ae(x,v);

			sz[v]+=sz[x];

		}

		cnt--;

	}

	print();

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5431718342940512x):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;



#define int ll

 

struct node{

	ll w;

	int y;

}a[100050];

 

struct node2{

	int t, nxt;

}edge[200050];

 

struct node3{int fr, f;};

 

int head[100050], cnt, n, siz[100050], anss;

 

void add(int u, int v){

	edge[++cnt] = (node2){v, head[u]};

	head[u] = cnt;

}

 

bool cmp(node a, node b){return a.w<b.w;}

 

int find(int u){

	for(int i = u-1; i >= 1; i--)if(a[i].w - a[u].w == 2*siz[a[u].y] - n) return a[i].y;

	return -1;

}

 

void print(int u, int fa){

	queue<node3> q;

	q.push((node3){u, fa});

	while(!q.empty()){

		u = q.front().fr;

		int ff = q.front().f;

		q.pop();

		for(int i = head[u]; i; i = edge[i].nxt){

			int v = edge[i].t;

			printf("%d %d\n", u, v);

			q.push((node3){v, u});

		}

	}

}



void test(int u, int fa, int dep){

	anss+=dep;

	for(int i = head[u]; i; i = edge[i].nxt){

		int v = edge[i].t;

		if(v == fa) continue;

		test(v, u, dep+1);

	}

}



main(){

	scanf("%d", &n);

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

		scanf("%lld", &a[i].w);

		a[i].y = i;

	}

	sort(a+1, a+n+1, cmp);

	int rt = a[1].y;

	for(int i = n; i >= 2; i--) {

		siz[a[i].y]++;

		int p = find(i);

		if(p == -1){

			printf("-1");

			return 0;

		}

		siz[p]+=siz[a[i].y];

		add(p, a[i].y);

	}

	test(rt, 0, 0);

	if(anss != a[1].w){

		printf("-1");

		return 0;

	}

	print(rt, 0);

}
// Slower C++ solution:
#include <cstdio>

#include <iostream>

#include <algorithm>

#include <cstring>

#include <map>

#include <queue>

#include <vector>

#define PB push_back

#define MP make_pair

#define ll long long

using namespace std;

template <class T>

inline void rd(T &x) {

	x=0; char c=getchar(); int f=1;

	while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }

	while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;

}

const int N=1e5+10;

struct node {

	int id; ll d;

	node(int id=0,ll d=0): id(id),d(d) {}

	friend bool operator <(node A,node B) { return A.d<B.d; }

};

priority_queue<node> que;

map<ll,int> mp;

int n,sz[N];

ll d[N];

vector< pair<int,int> > E;

vector<int> son[N];

ll dfs(int u) {

	ll tot=0;

	for(int i=0;i<son[u].size();++i) tot+=dfs(son[u][i])+sz[son[u][i]];

	return tot;

}

int main() {

	rd(n);

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

		rd(d[i]),mp[d[i]]=i;

		que.push(node(i,d[i]));

		sz[i]=1;

	}

	while(que.size()>1) {

		int u=que.top().id; que.pop();

		mp.erase(d[u]);

		ll t=d[u]-(n-sz[u]*2ll);

		if(!mp.count(t)) {

			printf("-1");

			return 0;

		}

		int f=mp[t];

		E.PB(MP(f,u));

		son[f].PB(u);

		sz[f]+=sz[u];

	}

	int rt=que.top().id;

	if(dfs(rt)!=d[rt]) {

		printf("-1");

		return 0;

	}

	for(int i=0;i<E.size();++i) printf("%d %d\n",E[i].first,E[i].second);

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5425765135076204x):
#include<bits/stdc++.h>

using namespace std;



typedef long long ll;



#define int ll

 

struct node{

	ll w;

	int y;

}a[100050];

 

struct node2{

	int t, nxt;

}edge[200050];

 

struct node3{int fr, f;};

 

int head[100050], cnt, n, siz[100050], anss;

 

void add(int u, int v){

	edge[++cnt] = (node2){v, head[u]};

	head[u] = cnt;

}

 

bool cmp(node a, node b){return a.w<b.w;}

 

int find(int u){

	for(int i = u-1; i >= 1; i--)if(a[i].w - a[u].w == 2*siz[a[u].y] - n) return a[i].y;

	return -1;

}

 

void print(int u, int fa){

	queue<node3> q;

	q.push((node3){u, fa});

	while(!q.empty()){

		u = q.front().fr;

		int ff = q.front().f;

		q.pop();

		for(int i = head[u]; i; i = edge[i].nxt){

			int v = edge[i].t;

			printf("%d %d\n", u, v);

			q.push((node3){v, u});

		}

	}

}



void test(int u, int fa, int dep){

	anss+=dep;

	for(int i = head[u]; i; i = edge[i].nxt){

		int v = edge[i].t;

		if(v == fa) continue;

		test(v, u, dep+1);

	}

}



main(){

	scanf("%d", &n);

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

		scanf("%lld", &a[i].w);

		a[i].y = i;

	}

	sort(a+1, a+n+1, cmp);

	int rt = a[1].y;

	for(int i = n; i >= 2; i--) {

		siz[a[i].y]++;

		int p = find(i);

		if(p == -1){

			printf("-1");

			return 0;

		}

		siz[p]+=siz[a[i].y];

		add(p, a[i].y);

	}

	test(rt, 0, 0);

	if(anss != a[1].w){

		printf("-1");

		return 0;

	}

	print(rt, 0);

}
// Slower C++ solution:
// Peace Of SHIT

#include<bits/stdc++.h>

#define int long long

using namespace std;

typedef pair<int, int> pii;

const int maxn = 1e5 + 5;

int n, si[maxn];

int sum = 0;

vector<int> e[maxn];

pii d[maxn];



void impossible() {

	cout << -1;

	exit(0);

}



void dfs(int u, int x) {

	sum += x;

	for(int i = 0; i < e[u].size(); i++) {

		dfs(e[u][i], x + 1);

	}

}



int32_t main() {

	cin >> n;

	for(int i = 0; i < n; i++) {

		int a;

		cin >> a;

		d[i] = {a, i};

	}

	sort(d, d + n);

	reverse(d, d + n);

	

	vector <pii> k (d, d + n);

	

	for(int q = 0; q < n - 1; q++) {

		int leaf = d[q].second;

		int parD = d[q].first - (n - (2 * (si[leaf] + 1)));

		auto it = lower_bound(k.rbegin(), k.rend(), pii(parD, 0));

//		cout << "PAR : " <<it->first << " : " << parD << '\n';

		if(it -> first != parD) {

//			cerr << "AVALI\n";

			impossible();

		}

		int par = it -> second;

		si[par] += si[leaf] + 1;

		if((si[leaf] + 1) * 2 > n) {

//			cout << "DOVOMI\n";

			impossible();

		}

		//SEVOMI HAM MISHE D[I] ROOT OK E ?

		e[par].push_back(leaf);

	}

	int D = d[n - 1].second;

	dfs(D, 0);

	if(sum != d[n - 1].first)

		impossible();

	for(int i = 0; i < n; i++) {

		for(int j = 0; j < e[i].size(); j++)

			cout << i + 1 << " " << e[i][j] + 1 <<'\n';

	}

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.606477469890699x):
#include <iostream>

#include <cstdio>

#include <algorithm>

#define int long long

#define ll long long

using namespace std;

inline int read()

{

	int x = 0, f = 1; char ch = getchar();

	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}

	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}

	return x * f;

}

const int N = 1e5 + 1000;

int n,num; ll dis,siz[N];

int u[N],to[N];

struct node

{

	ll v; int id;

	int friend operator <(node a,node b){return a.v < b.v;}

}p[N];

signed main()

{

	n = read();

	for(int i = 1;i <= n;i ++) {p[i] = node{read(),i}; siz[i] = 1;}

	sort(p + 1,p + 1 + n);

	for(int i = n;i > 1;i --)

	{

		ll Dis = p[i].v - n + (siz[i] << 1);

		int t = lower_bound(p + 1,p + 1 + n,node{Dis,0}) - p;

		if(p[t].v != Dis) {puts("-1"); return 0;}

		num ++; u[num] = p[i].id; to[num] = p[t].id;

		siz[t] += siz[i]; dis += siz[i]; 

	}

	if(dis != p[1].v) {puts("-1"); return 0;}

	else for(int i = 1;i < n;i ++) cout << u[i] << " " << to[i] << "\n";

}
// Slower C++ solution:
// Peace Of SHIT

#include<bits/stdc++.h>

#define int long long

using namespace std;

typedef pair<int, int> pii;

const int maxn = 1e5 + 5;

int n, si[maxn];

int sum = 0;

vector<int> e[maxn];

pii d[maxn];



void impossible() {

	cout << -1;

	exit(0);

}



void dfs(int u, int x) {

	sum += x;

	for(int i = 0; i < e[u].size(); i++) {

		dfs(e[u][i], x + 1);

	}

}



int32_t main() {

	scanf("%lld", &n);

	for(int i = 0; i < n; i++) {

		int a;

		scanf("%lld", &a);

		d[i] = {a, i};

	}

	sort(d, d + n);

	reverse(d, d + n);

	

	vector <pii> k (d, d + n);

	

	for(int q = 0; q < n - 1; q++) {

		int leaf = d[q].second;

		int parD = d[q].first - (n - (2 * (si[leaf] + 1)));

		auto it = lower_bound(k.rbegin(), k.rend(), pii(parD, 0));

//		cout << "PAR : " <<it->first << " : " << parD << '\n';

		if(it -> first != parD) {

//			cerr << "AVALI\n";

			impossible();

		}

		int par = it -> second;

		si[par] += si[leaf] + 1;

		if((si[leaf] + 1) * 2 > n) {

//			cout << "DOVOMI\n";

			impossible();

		}

		//SEVOMI HAM MISHE D[I] ROOT OK E ?

		e[par].push_back(leaf);

	}

	int D = d[n - 1].second;

	dfs(D, 0);

	if(sum != d[n - 1].first)

		impossible();

	for(int i = 0; i < n; i++) {

		for(int j = 0; j < e[i].size(); j++) {

			printf("%lld %lld\n", i + 1, e[i][j] + 1);

		}

	}

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5976096987510306x):
#include <iostream>

#include <cstdio>

#include <algorithm>

#define int long long

#define ll long long

using namespace std;

inline int read()

{

	int x = 0, f = 1; char ch = getchar();

	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}

	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}

	return x * f;

}

const int N = 1e5 + 1000;

int n,num; ll dis,siz[N];

int u[N],to[N];

struct node

{

	ll v; int id;

	int friend operator <(node a,node b){return a.v < b.v;}

}p[N];

signed main()

{

	n = read();

	for(int i = 1;i <= n;i ++) {p[i] = node{read(),i}; siz[i] = 1;}

	sort(p + 1,p + 1 + n);

	for(int i = n;i > 1;i --)

	{

		ll Dis = p[i].v - n + (siz[i] << 1);

		int t = lower_bound(p + 1,p + 1 + n,node{Dis,0}) - p;

		if(p[t].v != Dis) {puts("-1"); return 0;}

		num ++; u[num] = p[i].id; to[num] = p[t].id;

		siz[t] += siz[i]; dis += siz[i]; 

	}

	if(dis != p[1].v) {puts("-1"); return 0;}

	else for(int i = 1;i < n;i ++) cout << u[i] << " " << to[i] << "\n";

}
// Slower C++ solution:
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N=100100;



map<LL,int> qaq;



void DSY(){

	puts("-1");

	exit(0);

}



int sz[N];



vector<int> es[N];

LL dd[N]={0};

LL d[N];

void dsy(int x,int fa=-1){

	for(vector<int>::iterator it=es[x].begin();it!=es[x].end();++it){

		if(*it==fa)continue;

		dsy(*it,x);

		dd[x]+=dd[*it]+sz[*it];

	}

}



vector<pair<int,int> > ess;

void ae(int u,int v){

	if(u>v)swap(u,v);

	ess.push_back(pair<int,int>(u,v));

	es[u].push_back(v);

	es[v].push_back(u);

}

void print(){

	sort(ess.begin(),ess.end());

	for(vector<pair<int,int> >::iterator it=ess.begin();it!=ess.end();++it){

		printf("%d %d\n",it->first,it->second);

	}

}



int main(){

	int n;

	scanf("%d",&n);

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

		scanf("%lld",&d[i]);

		qaq[d[i]]=i;

		sz[i]=1;

	}

	int cnt=n;

	for(map<LL,int>::reverse_iterator it=qaq.rbegin();it!=qaq.rend();++it){

		int x=it->second;

		LL ddd=it->first;

		if(sz[x]*2==n)DSY();

		LL nd=ddd+sz[x]-(n-sz[x]);

		if(cnt==1){

			dsy(x);

			if(dd[x]!=d[x])DSY();

			break;

		}

		if(!qaq.count(nd)){

			DSY();

		}else{

			int v=qaq[nd];

			ae(x,v);

			sz[v]+=sz[x];

		}

		cnt--;

	}

	print();

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5865219398469175x):
#include <iostream>

#include <cstdio>

#include <algorithm>

#define int long long

#define ll long long

using namespace std;

inline int read()

{

	int x = 0, f = 1; char ch = getchar();

	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}

	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}

	return x * f;

}

const int N = 1e5 + 1000;

int n,num; ll dis,siz[N];

int u[N],to[N];

struct node

{

	ll v; int id;

	int friend operator <(node a,node b){return a.v < b.v;}

}p[N];

signed main()

{

	n = read();

	for(int i = 1;i <= n;i ++) {p[i] = node{read(),i}; siz[i] = 1;}

	sort(p + 1,p + 1 + n);

	for(int i = n;i > 1;i --)

	{

		ll Dis = p[i].v - n + (siz[i] << 1);

		int t = lower_bound(p + 1,p + 1 + n,node{Dis,0}) - p;

		if(p[t].v != Dis) {puts("-1"); return 0;}

		num ++; u[num] = p[i].id; to[num] = p[t].id;

		siz[t] += siz[i]; dis += siz[i]; 

	}

	if(dis != p[1].v) {puts("-1"); return 0;}

	else for(int i = 1;i < n;i ++) cout << u[i] << " " << to[i] << "\n";

}
// Slower C++ solution:
#include <cstdio>

#include <iostream>

#include <algorithm>

#include <cstring>

#include <map>

#include <queue>

#include <vector>

#define PB push_back

#define MP make_pair

#define ll long long

using namespace std;

template <class T>

inline void rd(T &x) {

	x=0; char c=getchar(); int f=1;

	while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }

	while(isdigit(c)) x=x*10-'0'+c,c=getchar(); x*=f;

}

const int N=1e5+10;

struct node {

	int id; ll d;

	node(int id=0,ll d=0): id(id),d(d) {}

	friend bool operator <(node A,node B) { return A.d<B.d; }

};

priority_queue<node> que;

map<ll,int> mp;

int n,sz[N];

ll d[N];

vector< pair<int,int> > E;

vector<int> son[N];

ll dfs(int u) {

	ll tot=0;

	for(int i=0;i<son[u].size();++i) tot+=dfs(son[u][i])+sz[son[u][i]];

	return tot;

}

int main() {

	rd(n);

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

		rd(d[i]),mp[d[i]]=i;

		que.push(node(i,d[i]));

		sz[i]=1;

	}

	while(que.size()>1) {

		int u=que.top().id; que.pop();

		mp.erase(d[u]);

		ll t=d[u]-(n-sz[u]*2ll);

		if(!mp.count(t)) {

			printf("-1");

			return 0;

		}

		int f=mp[t];

		E.PB(MP(f,u));

		son[f].PB(u);

		sz[f]+=sz[u];

	}

	int rt=que.top().id;

	if(dfs(rt)!=d[rt]) {

		printf("-1");

		return 0;

	}

	for(int i=0;i<E.size();++i) printf("%d %d\n",E[i].first,E[i].second);

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.585919335411785x):
#include <iostream>

#include <cstdio>

#include <algorithm>

#define int long long

#define ll long long

using namespace std;

inline int read()

{

	int x = 0, f = 1; char ch = getchar();

	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}

	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}

	return x * f;

}

const int N = 1e5 + 1000;

int n,num; ll dis,siz[N];

int u[N],to[N];

struct node

{

	ll v; int id;

	int friend operator <(node a,node b){return a.v < b.v;}

}p[N];

signed main()

{

	n = read();

	for(int i = 1;i <= n;i ++) {p[i] = node{read(),i}; siz[i] = 1;}

	sort(p + 1,p + 1 + n);

	for(int i = n;i > 1;i --)

	{

		ll Dis = p[i].v - n + (siz[i] << 1);

		int t = lower_bound(p + 1,p + 1 + n,node{Dis,0}) - p;

		if(p[t].v != Dis) {puts("-1"); return 0;}

		num ++; u[num] = p[i].id; to[num] = p[t].id;

		siz[t] += siz[i]; dis += siz[i]; 

	}

	if(dis != p[1].v) {puts("-1"); return 0;}

	else for(int i = 1;i < n;i ++) cout << u[i] << " " << to[i] << "\n";

}
// Slower C++ solution:
#include<cstdio>

#include<cstring>

#include<algorithm>

#include<map>

#define MN 100005

#define ll long long

using namespace std;

inline ll in(){

    ll x=0;bool f=0;char c;

    for (;(c=getchar())<'0'||c>'9';f=c=='-');

    for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');

    return f?-x:x;

}

struct st{

	ll v;

	int id;

}a[MN];

struct edge{

	int to,nxt;

}e[MN<<1];

map <ll,int> mp;

int h[MN],fa[MN],dep[MN],siz[MN];

int n,cnt;

ll sum;

inline bool cmp(st x,st y){return x.v>y.v;}

inline void ins(int x,int y){

	e[++cnt].to=y;e[cnt].nxt=h[x];h[x]=cnt;

}

inline void dfs(int u){

	sum+=1ll*dep[u];

	for (int i=h[u];i;i=e[i].nxt){

		int v=e[i].to;

		if (v==fa[u]) continue;

		dep[v]=dep[u]+1;

		fa[v]=u;dfs(v);

	}

}

int main()

{

	n=in();

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

		a[i].v=in();a[i].id=i;

		mp[a[i].v]=i;siz[i]=1;

	}sort(a+1,a+n+1,cmp);

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

		ll d=a[i].v-n+(siz[a[i].id]<<1);

		if (d>=a[i].v||(!mp[d])) {printf("-1");return 0;}

		ins(a[i].id,mp[d]);ins(mp[d],a[i].id);

		siz[mp[d]]+=siz[a[i].id];

	}dfs(a[n].id);

	if (sum!=a[n].v) {printf("-1");return 0;}

	for (int i=1;i<=n;++i)

	if (fa[i]) printf("%d %d\n",fa[i],i);return 0;

}

// Faster C++ solution for the same problem (measured speedup: 4.829632496356739x):
#include <cstdio>

#include <algorithm>

#include <vector>

#define file(x) freopen(#x".in", "r", stdin), freopen(#x".out", "w", stdout)



const int N(1e5 + 10);

struct edge { int x, y; } e[N];

struct node { long long d; int id; } a[N];

inline int operator < (const node &l, const node &r)

	{ return l.d < r.d; }

int n, size[N], cnt;



int main()

{

	scanf("%d", &n);

	for (int i = 1; i <= n; i++)

		scanf("%lld", &a[i].d), a[i].id = i, size[i] = 1;

	std::sort(a + 1, a + n + 1);

	long long dis = 0, d;

	for (int i = n, p; i > 1; i--)

	{

		d = a[i].d - n + (size[i] << 1), p = std::lower_bound(a + 1, a + n + 1, (node) {d, 0}) - a;

		if (a[p].d != d) return puts("-1"), 0;

		e[++cnt] = (edge) {a[i].id, a[p].id}, size[p] += size[i], dis += size[i];

	}

	if (dis != a[1].d) puts("-1");

	else for (int i = 1; i < n; i++) printf("%d %d\n", e[i].x, e[i].y);

	return 0;

}