stablegradients/pie-gem5-bysrc huggingface dataset:
// Original C++ solution (slower):
#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;

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#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;

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#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;

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include <cstdio>

#include <algorithm>

#include <numeric>

#include <map>

#define fail return puts("-1"), 0



const int N = 1e5 + 5, M = 2e5 + 5;



int n, tot, lnk[N], ter[M], nxt[M], sz[N];

long long dis[N], d[N];

std::map<long long, int> mp;



void add(int u, int v) {

	ter[++tot] = v, nxt[tot] = lnk[u], lnk[u] = tot;

}

void dfs(int u, int p) {

	for (int i = lnk[u]; i; i = nxt[i]) {

		int v = ter[i];

		if (v == p) continue;

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

		dfs(v, u);

	}

}

int main() {

	scanf("%d", &n);

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

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

		mp[d[i]] = i, sz[i] = 1;

	}

	int cnt = 0;

	for (auto it = mp.rbegin(); it != mp.rend(); it++) {

		int v = it->second, u = mp[it->first + 2 * sz[v] - n];

		if (!u || u == v) fail;

		add(u, v), add(v, u), sz[u] += sz[v];

		if (++cnt == n - 1) break;

	}

	int rt = mp.begin()->second;

	dfs(rt, 0);

	if (std::accumulate(dis + 1, dis + n + 1, 0LL) != d[rt]) fail;

	for (int i = 1; i <= tot; i += 2) {

		printf("%d %d\n", ter[i], ter[i + 1]);

	}

	return 0;

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>

using namespace std;

#define ll long long

#define re register

#define gc getchar

#define pc putchar

#define cs const



inline

ll getint(){

	re ll num;

	re char c;

	while(!isdigit(c=gc()));num=c^48;

	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);

	return num;

}



inline

void outint(int a){

	static char ch[13];

	if(a==0)pc('0');

	while(a)ch[++ch[0]]=a-a/10*10,a/=10;

	while(ch[0])pc(ch[ch[0]--]^48);

}



cs int N=100005;



int last[N],nxt[N],to[N],ecnt;

inline

void addedge(int u,int v){

	nxt[++ecnt]=last[u],last[u]=ecnt,to[ecnt]=v;

}



map<ll,int> id;

int n;

ll d[N];

int siz[N];



int dist[N];

inline

void dfs(int u){

	for(int re e=last[u],v=to[e];e;v=to[e=nxt[e]]){

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

		dfs(v);

	}

}



vector<pair<int,int> > edge;



signed main(){

	n=getint();

	for(int re i=1;i<=n;++i)d[i]=getint(),id[d[i]]=i;

	

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

	for(int re i=1;i<=n;++i)siz[i]=1;

	

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

		int u=id[d[i]];

		int tmp=n-2*siz[u];

		if(tmp<=0)return puts("-1"),0; 

		ll t=d[i]-tmp;

		if(id.count(t)==0)return puts("-1"),0;

		int pos=id[t];

		addedge(pos,u);

		siz[pos]+=siz[u];

		edge.push_back(make_pair(pos,u));

	}

	ll sum=0;

	dfs(id[d[1]]);

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

		sum+=dist[i];

	}

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

	for(int re i=0;i<edge.size();++i)outint(edge[i].first),pc(' '),outint(edge[i].second),pc('\n');

	return 0;

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>

using namespace std;



#define int long long



#define pii pair<int,int> 



int N;

int a[100010];

map<int,int> mp;



vector<pii> e;

int sz[100010];

int dp[100010];



vector<pii> ans;



bool cmp_d(pii p,pii q)

{

	return p>q;

}



pii norm(int p,int q)

{

	return {min(p,q),max(p,q)};

}



main()

{

	cin>>N;

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

	{

		cin>>a[i];

		mp[a[i]]=i;

		e.push_back({a[i],i});

		sz[i]=1;

	}

	sort(e.begin(),e.end(),cmp_d);

	int x=e.back().first;

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

	{

		pii& cur=e[i];

		if(cur.first!=x)

		{

			if(sz[cur.second]*2>=N) goto FAIL;

			int p=cur.first-N+2*sz[cur.second];

			if(mp.find(p)==mp.end()) goto FAIL;

			int q=mp[p];

			dp[q]+=dp[cur.second]+sz[cur.second];

			sz[q]+=sz[cur.second];

			ans.push_back(norm(cur.second,q));

		}

	}

	if(dp[e.back().second]!=x) goto FAIL;

	

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

	for(int i=0;i<ans.size();i++)

	{

		cout<<ans[i].first<<" "<<ans[i].second<<endl;

	}

	return 0;

	

	

	

	FAIL:;

	{

		cout<<"-1"<<endl;

		return 0;

	}

}














// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<stdio.h>

#include<algorithm>

#include<iostream>

#include<map>

#include<vector>

#define ll long long

#define pii pair<int,int>

#define MP make_pair

using namespace std;

ll n;

map<ll,int>rev;

struct node{ll d,siz,val;int id;}a[100005];

bool cmp(node x,node y){return x.d>y.d;}

int back[100005];

vector<pii>ans;

int main(){

    scanf("%d",&n);

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

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

        a[i].siz=1;a[i].id=i;

        rev[a[i].d]=i;

    }

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

    for(int i=1;i<=n;i++) back[a[i].id]=i;

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

        if(n-2*a[i].siz<=0){puts("-1");return 0;}

        ll dd=a[i].d+2*a[i].siz-n;

        if(!rev[dd]){puts("-1");return 0;}

        int fa=rev[dd];

        ans.push_back(MP(min(fa,a[i].id),max(fa,a[i].id)));

        a[back[fa]].siz+=a[i].siz;

        a[back[fa]].val+=a[i].val+a[i].siz;

    }

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

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

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

    return 0;

}


// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#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);

}

// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#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";

}


// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem:
// Original C++ solution (slower):
#include<bits/stdc++.h>



#define LL long long

#define RG register



using namespace std;

template<class T> T gi() {

	T x = 0; bool f = 0; char c = getchar();

	while (c != '-' && (c < '0' || c > '9')) c = getchar();

	if (c == '-') f = 1, c = getchar();

	while (c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();

	return f ? -x : x;

}

const int N = 1e5 + 10;

int p[N], siz[N], X[N], Y[N], fa[N];

int find(int x) { return fa[x] == x ? x : fa[x] = find(fa[x]); }

LL D[N];

map<LL, int> M;

vector<int> e[N];

bool cmp(int x, int y) { return D[x] > D[y]; }

LL res;

void dfs(int u, int ff) {

	siz[u] = 1;

	for (auto v : e[u])

		if (v != ff) {

			dfs(v, u);

			res += siz[v];

			siz[u] += siz[v];

		}

}

int main() {

	//freopen(".in", "r", stdin);

	//freopen(".out", "w", stdout);

	int n = gi<int>();

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

		D[i] = gi<LL>(), M[D[i]] = i, p[i] = i;

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

	for (int i = 1; i <= n; i++) siz[i] = 1, fa[i] = i;

	int cnt = 0;

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

		int x = p[i];		

		if (M.find(D[x] - n + 2 * siz[x]) == M.end()) continue;

		int y = M[D[x] - n + 2 * siz[x]];

		if (find(x) == find(y)) continue;

		fa[find(y)] = find(x);

		siz[y] += siz[x]; X[++cnt] = x; Y[cnt] = y;

		e[x].push_back(y); e[y].push_back(x);

	}

	dfs(1, 0);

	if (cnt < n - 1 || res != D[1])

		puts("-1");

	else

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

			printf("%d %d\n", X[i], Y[i]);	

	return 0;

}


// Optimized solution to the same problem (faster):
#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;

}


// Fastest known solution for this problem: