stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#include <bits/stdc++.h>

#define fail return (cout << -1 << endl), 0

#define ll long long



using namespace std;



int n;

map<ll, int> f;

ll dis[100010], rdis[100010];

int sz[100010];



struct Edge {

	int to, next;

}es[200010];

int first[100010], te = 0;



void addE(int a, int b)

{

	te++;

	es[te].to = b;

	es[te].next = first[a];

	first[a] = te; 

}



void dfs(int p, int fa)

{

	if (p != 1) rdis[p] = rdis[fa] + 1;

	for (int e = first[p]; e; e = es[e].next)

	{

		int to = es[e].to;

		if (to == fa) continue;

		dfs(to, p); 

	}

}



int main()

{

	ios::sync_with_stdio(false);

	cin >> n;

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

	{

		cin >> dis[i];

		f[dis[i]] = i;

		sz[i] = 1;

	}

	int cnt = 0;

	for (map<ll, int>::reverse_iterator it = f.rbegin(); it != f.rend(); it++)

	{

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

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

		addE(u, v); addE(v, u);

		sz[u] += sz[v];

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

	}

	dfs(1, 0);

	ll sum = 0;

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

		sum += rdis[i];

	if (sum != dis[1]) fail;

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

		for (int e = first[i]; e; e = es[e].next)

		{

			if (e & 1) continue;

			cout << i << ' ' << es[e].to << endl;

		}

	return 0;

}


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

#include<map>

using namespace std;

typedef long long ll;

map<ll,int>p;

map<ll,int>::iterator it;

int fa[100010],siz[100010],a[100010],b[100010],h[100010],nex[200010],to[200010],M,n;

void add(int a,int b){

    M++;

    to[M]=b;

    nex[M]=h[a];

    h[a]=M;

}

ll wd[100010],d[100010];

void dfs(int x,int dis){

    siz[x]=1;

    d[1]+=dis;

    for(int i=h[x];i;i=nex[i]){

        if(to[i]!=fa[x]){

            fa[to[i]]=x;

            dfs(to[i],dis+1);

            siz[x]+=siz[to[i]];

        }

    }

}

void dfs(int x){

    for(int i=h[x];i;i=nex[i]){

        if(to[i]!=fa[x]){

            d[to[i]]=d[x]+n-siz[to[i]]*2;

            dfs(to[i]);

        }

    }

}

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

int main(){

    int i;

    scanf("%d",&n);

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

        scanf("%lld",wd+i);

        p[wd[i]]=i;

    }

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

        fa[i]=i;

        siz[i]=1;

    }

    it=p.end();

    for(it--;it!=p.begin();it--){

        if(n-siz[it->second]*2==0||!p.count(it->first-(n-siz[it->second]*2))){

            puts("-1");

            return 0;

        }

        M++;

        a[M]=it->second;

        b[M]=p[it->first-(n-siz[it->second]*2)];

        siz[fa[a[M]]=get(b[M])]+=siz[a[M]];

    }

    M=0;

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

        add(a[i],b[i]);

        add(b[i],a[i]);

    }

    fa[1]=0;

    dfs(1,0);

    dfs(1);

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

        if(wd[i]!=d[i]){

            puts("-1");

            return 0;

        }

    }

    for(i=1;i<n;i++)printf("%d %d\n",a[i],b[i]);

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

#define fail return (cout << -1 << endl), 0

#define ll long long



using namespace std;



int n;

map<ll, int> f;

ll dis[100010], rdis[100010];

int sz[100010];



struct Edge {

	int to, next;

}es[200010];

int first[100010], te = 0;



void addE(int a, int b)

{

	te++;

	es[te].to = b;

	es[te].next = first[a];

	first[a] = te; 

}



void dfs(int p, int fa)

{

	if (p != 1) rdis[p] = rdis[fa] + 1;

	for (int e = first[p]; e; e = es[e].next)

	{

		int to = es[e].to;

		if (to == fa) continue;

		dfs(to, p); 

	}

}



int main()

{

	ios::sync_with_stdio(false);

	cin >> n;

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

	{

		cin >> dis[i];

		f[dis[i]] = i;

		sz[i] = 1;

	}

	int cnt = 0;

	for (map<ll, int>::reverse_iterator it = f.rbegin(); it != f.rend(); it++)

	{

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

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

		addE(u, v); addE(v, u);

		sz[u] += sz[v];

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

	}

	dfs(1, 0);

	ll sum = 0;

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

		sum += rdis[i];

	if (sum != dis[1]) fail;

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

		for (int e = first[i]; e; e = es[e].next)

		{

			if (e & 1) continue;

			cout << i << ' ' << es[e].to << endl;

		}

	return 0;

}


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

#include<map>

using namespace std;

typedef long long ll;

map<ll,int>p;

map<ll,int>::iterator it;

int fa[100010],siz[100010],a[100010],b[100010],h[100010],nex[200010],to[200010],M,n;

void add(int a,int b)

{

    M++;

    to[M]=b;

    nex[M]=h[a];

    h[a]=M;

}

ll wd[100010],d[100010];

void dfs(int x,int dis)

{

    siz[x]=1;

    d[1]+=dis;

    for(int i=h[x];i;i=nex[i])if(to[i]!=fa[x])

	{

        fa[to[i]]=x;

        dfs(to[i],dis+1);

        siz[x]+=siz[to[i]];

    }

}

void dfs(int x)

{

    for(int i=h[x];i;i=nex[i])if(to[i]!=fa[x])

	{

        d[to[i]]=d[x]+n-siz[to[i]]*2;

        dfs(to[i]);

    }

}

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

int main()

{

    int i;

    scanf("%d",&n);

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

	{

        scanf("%lld",wd+i);

        p[wd[i]]=i;

    }

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

	{

        fa[i]=i;

        siz[i]=1;

    }

    it=p.end();

    for(it--;it!=p.begin();it--)

	{

        if(n-siz[it->second]*2==0||!p.count(it->first-(n-siz[it->second]*2)))

		{

            puts("-1");

            return 0;

        }

        M++;

        a[M]=it->second;

        b[M]=p[it->first-(n-siz[it->second]*2)];

        siz[fa[a[M]]=get(b[M])]+=siz[a[M]];

    }

    M=0;

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

	{

        add(a[i],b[i]);

        add(b[i],a[i]);

    }

    fa[1]=0;

    dfs(1,0);

    dfs(1);

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

	{

        if(wd[i]!=d[i])

		{

            puts("-1");

            return 0;

        }

    }

    for(i=1;i<n;i++)printf("%d %d\n",a[i],b[i]);

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

#define R register

typedef long long ll;

typedef std::pair<ll, int> pii;



const int MN = 1e5 + 5;



pii d[MN];



std::map<ll, int> mp;



int n, fa[MN], sz[MN], rt;



ll dp[MN];



struct Edge {

	int to;

	Edge *nxt;

	Edge(Edge *nxt = nullptr, int to = 0) : to(to), nxt(nxt){}

}*hd[MN];



inline void ins(int u, int v) {hd[u] = new Edge(hd[u], v);}



void dfs(int u) {

	for (R Edge *e = hd[u]; e != nullptr; e = e -> nxt) {

		R int v = e -> to;

		dfs(v);

		dp[u] += sz[v] + dp[v];

	}

}



void solve(int u) {

	for (R Edge *e = hd[u]; e != nullptr; e = e -> nxt) {

		R int v = e -> to;

		dp[v] += (n - sz[v]) + (dp[u] - dp[v] - sz[v]);

		solve(v);

	}

}



int main() {

	std::ios::sync_with_stdio(false);



	std::cin >> n;

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

		R ll x;

		std::cin >> x;

		mp[x] = i;

		d[i] = pii(x, i);

		sz[i] = 1;

	}

	

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

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

		R int v = d[i].second;

		R ll res = d[i].first;

		if (mp[res + (sz[v] << 1) - n])	 {

			fa[v] = mp[res + (sz[v] << 1) - n];

			sz[fa[v]] += sz[v];

		}

		else {

			std::cout << "-1" << std::endl;

			return 0;

		}

	}

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

		if (fa[i]) ins(fa[i], i);

		else rt = i;

	dfs(rt);

	solve(rt);

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

		if (dp[d[i].second] != d[i].first){

			std::cout << "-1" << std::endl;

			return 0;

		}



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

		if (fa[i])

			std::cout << fa[i] << " " << i << std::endl;

	return 0;

}

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

#include <cstdio>

#include <cstring>



#define int long long

#define Accepted 0; 



const int Maxv = 100010; 

int d[Maxv], d1[Maxv], u[Maxv], ghostfly233[Maxv], siz[Maxv], cnt, n;  



inline int GldHkkowoSearch(int x) {

    int tmp = std::lower_bound(d + 1, d + n + 1, x) - d;



    if (d[tmp] != x) {

        puts("-1"); 

        exit(0); 

    }



    return tmp; 

}



signed main() {

    scanf("%lld", &n); 

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

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

        d1[i] = d[i]; 

    }



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

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

        ghostfly233[GldHkkowoSearch(d1[i])] = i;       



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

        siz[i] = 1; 



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

        u[i] = GldHkkowoSearch(d[i] - n + (siz[i] << 1)); 

        siz[ u[i] ] += siz[i]; 

        cnt += siz[i]; 

    }



    if (cnt != d[1]) {

        puts("-1"); 

        return 0; 

    }



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

        printf("%lld %lld\n", ghostfly233[i], ghostfly233[ u[i] ]); 



    return Accepted;  

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

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

#include<cmath>

#include<map>

#define ll long long

using namespace std;

map<ll,int> us;

ll d[100010];

ll che=0;

int n,cnt=0;

struct node{

	int to,nxt,cap;

}e[200010];

int pos[100010],siz[100010],head[100010],ansa[100010],ansb[100010];

bool cmp(int a,int b){

	return d[a]>d[b];

}

void add(int u,int v){

	e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;

	e[++cnt].to=u;e[cnt].nxt=head[v];head[v]=cnt;

}

void dfs(int x,int fa,int dep){

	che+=dep;

	int i;

	for(i=head[x];i;i=e[i].nxt){

		if(e[i].to==fa)  continue ;

		dfs(e[i].to,x,dep+1);

	}

}

int main(){

	scanf("%d",&n);

	int i,j;

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

		scanf("%lld",&d[i]);us[d[i]]=i;siz[i]=1;pos[i]=i;

	}

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

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

		ll x=d[pos[i]]-(n-siz[pos[i]])+siz[pos[i]];

		if(!us[x] || x>=d[pos[i]]){printf("-1\n");return 0;}

		ansa[i]=us[x];ansb[i]=pos[i];

		add(us[x],pos[i]);

		siz[us[x]]+=siz[pos[i]];

	}

	dfs(pos[n],0,0);

	if(che!=d[pos[n]]){printf("-1\n");return 0;}

	for(i=1;i<n;++i)  printf("%d %d\n",ansa[i],ansb[i]);

	return 0;

}

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

#include <cstdio>

#include <cstring>



#define int long long

#define Accepted 0; 



const int Maxv = 100010; 

int d[Maxv], d1[Maxv], u[Maxv], ghostfly233[Maxv], siz[Maxv], cnt, n;  



inline int GldHkkowoSearch(int x) {

    int tmp = std::lower_bound(d + 1, d + n + 1, x) - d;



    if (d[tmp] != x) {

        puts("-1"); 

        exit(0); 

    }



    return tmp; 

}



signed main() {

    scanf("%lld", &n); 

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

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

        d1[i] = d[i]; 

    }



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

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

        ghostfly233[GldHkkowoSearch(d1[i])] = i;       



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

        siz[i] = 1; 



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

        u[i] = GldHkkowoSearch(d[i] - n + (siz[i] << 1)); 

        siz[ u[i] ] += siz[i]; 

        cnt += siz[i]; 

    }



    if (cnt != d[1]) {

        puts("-1"); 

        return 0; 

    }



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

        printf("%lld %lld\n", ghostfly233[i], ghostfly233[ u[i] ]); 



    return Accepted;  

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

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#define rep(i,l,r) for(int i=(l);i<=(r);++i)

#define per(i,r,l) for(int i=(r);i>=(l);--i)

using namespace std;

typedef long long ll;

const int maxn=1e5+10;

int n,sz[maxn],fa[maxn],d[maxn];

ll b[maxn],D;

vector<int> G[maxn];

struct Node{ll x;int id;}a[maxn];

inline bool operator <(Node x,Node y){return x.x<y.x;}

void dfs(int u,int fa){

    for(int v:G[u]) if(v!=fa) d[v]=d[u]+1,dfs(v,u);

}

int main(){

    scanf("%d",&n);

    rep(i,1,n) scanf("%lld",&a[i].x),a[i].id=i,b[i]=a[i].x;

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

    rep(i,1,n) sz[i]=1;

    per(i,n,2){

        int u=a[i].id;

        if(n%2==0&&sz[u]==n/2) return puts("-1"),0;

        int x=lower_bound(b+1,b+n+1,a[i].x-(n-2*sz[u]))-b;

        if(b[x]!=a[i].x-(n-sz[u])+sz[u]) return puts("-1"),0;

        x=a[x].id;fa[u]=x;sz[x]+=sz[u];

    }

    rep(i,1,n) G[i].push_back(fa[i]),G[fa[i]].push_back(i);

    dfs(a[1].id,0);

    rep(i,1,n) D+=d[i];if(D!=a[1].x) return puts("-1"),0; 

    rep(i,1,n) if(fa[i]) printf("%d %d\n",i,fa[i]);

    return 0;

}

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

#define maxn 100003

using namespace std;

struct edge{int to,next;}e[maxn<<1];

int head[maxn],cnte,fa[maxn];

void add(int u,int v){e[++cnte].to=v,e[cnte].next=head[u],head[u]=cnte;}

int n,sz[maxn],s[maxn];

long long d[maxn],sum;

map<long long,int> b;

bool cmp(int x,int y){return d[x]<d[y];}

void dfs(int u,int depth){

	sum+=depth;

	for(int i=head[u];i;i=e[i].next){

		int v=e[i].to;

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

		dfs(v,depth+1);

	}

}

int main(){

	scanf("%d",&n);

	for(int i=1;i<=n;i++)scanf("%lld",d+i),s[i]=i,b[d[i]]=i,sz[i]=1;

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

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

		int v=s[i];

		long long d_u=d[v]-(n-sz[v])+sz[v];

		if(d_u>=d[v]||!b.count(d_u)){puts("-1");return 0;}

		int u=b[d_u];

		add(u,v),add(v,u),fa[v]=u;

		sz[u]+=sz[v];

	}

	if(cnte!=(n-1)*2){puts("-1");return 0;}

	dfs(s[1],0);

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

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

		for(int i=head[u];i;i=e[i].next){

			int v=e[i].to;

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

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

		}

	}

	return 0;

}

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

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#define rep(i,l,r) for(int i=(l);i<=(r);++i)

#define per(i,r,l) for(int i=(r);i>=(l);--i)

using namespace std;

typedef long long ll;

const int maxn=1e5+10;

int n,sz[maxn],fa[maxn],d[maxn];

ll b[maxn],D;

vector<int> G[maxn];

struct Node{ll x;int id;}a[maxn];

inline bool operator <(Node x,Node y){return x.x<y.x;}

void dfs(int u,int fa){

    for(int v:G[u]) if(v!=fa) d[v]=d[u]+1,dfs(v,u);

}

int main(){

    scanf("%d",&n);

    rep(i,1,n) scanf("%lld",&a[i].x),a[i].id=i,b[i]=a[i].x;

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

    rep(i,1,n) sz[i]=1;

    per(i,n,2){

        int u=a[i].id;

        if(n%2==0&&sz[u]==n/2) return puts("-1"),0;

        int x=lower_bound(b+1,b+n+1,a[i].x-(n-2*sz[u]))-b;

        if(b[x]!=a[i].x-(n-sz[u])+sz[u]) return puts("-1"),0;

        x=a[x].id;fa[u]=x;sz[x]+=sz[u];

    }

    rep(i,1,n) G[i].push_back(fa[i]),G[fa[i]].push_back(i);

    dfs(a[1].id,0);

    rep(i,1,n) D+=d[i];if(D!=a[1].x) return puts("-1"),0; 

    rep(i,1,n) if(fa[i]) printf("%d %d\n",i,fa[i]);

    return 0;

}

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

using namespace std;

const int N=2e5+3;

int n,siz[N],he[N],e;

long long anss;

struct syzs{

	long long val;

	int num;

} a[N];

struct ans{

	int e1,e2;

	bool operator <(const ans &emm) const{

	    if(emm.e1==e1) return e2>emm.e2;

		return emm.e1<e1;

	}

};

struct edg{

	int ne,to;

} edg[N];

bool cmp(syzs c,syzs b){

	return c.val>b.val;

}

int find(int k){

	long long chec=2*siz[k]-n;

	for(int i=k+1;i<=n;i++) if(a[i].val-a[k].val==chec) return i;

	return -1;

}

long long read(){

	long long s=0,f=1;

	char ch=getchar();

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

	while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}

	return s*f;

}

void add(int u,int v){

	edg[++e].to=v;

	edg[e].ne=he[u];

	he[u]=e;

}

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

	anss+=dep;

	for(int i=he[u];i;i=edg[i].ne){

		int v =edg[i].to;

		if(v==fa) continue;

		test(v,u,dep+1);

	}

}

int main(){

    priority_queue <ans> q;

	cin>>n;

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

		a[i].val=read();//scanf("%lld",&a[i].val);

		a[i].num=i;

		siz[i]=1;

	}

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

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

		int v=find(i);

		if(v==-1){

			cout<<-1<<endl;

			return 0;

		}

		siz[v]+=siz[i];

		add(a[i].num,a[v].num);

		add(a[v].num,a[i].num);

		q.push((ans) {min(a[v].num,a[i].num),max(a[v].num,a[i].num)});

	}

	test(a[1].num,0,0);

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

		cout<<-1<<endl;

		return 0;

	}

	while(!q.empty()){

		int v1=q.top().e1,v2=q.top().e2;

    	q.pop();

    	printf("%d %d\n",v1,v2);

	}

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

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#define rep(i,l,r) for(int i=(l);i<=(r);++i)

#define per(i,r,l) for(int i=(r);i>=(l);--i)

using namespace std;

typedef long long ll;

const int maxn=1e5+10;

int n,sz[maxn],fa[maxn],d[maxn];

ll b[maxn],D;

vector<int> G[maxn];

struct Node{ll x;int id;}a[maxn];

inline bool operator <(Node x,Node y){return x.x<y.x;}

void dfs(int u,int fa){

    for(int v:G[u]) if(v!=fa) d[v]=d[u]+1,dfs(v,u);

}

int main(){

    scanf("%d",&n);

    rep(i,1,n) scanf("%lld",&a[i].x),a[i].id=i,b[i]=a[i].x;

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

    rep(i,1,n) sz[i]=1;

    per(i,n,2){

        int u=a[i].id;

        if(n%2==0&&sz[u]==n/2) return puts("-1"),0;

        int x=lower_bound(b+1,b+n+1,a[i].x-(n-2*sz[u]))-b;

        if(b[x]!=a[i].x-(n-sz[u])+sz[u]) return puts("-1"),0;

        x=a[x].id;fa[u]=x;sz[x]+=sz[u];

    }

    rep(i,1,n) G[i].push_back(fa[i]),G[fa[i]].push_back(i);

    dfs(a[1].id,0);

    rep(i,1,n) D+=d[i];if(D!=a[1].x) return puts("-1"),0; 

    rep(i,1,n) if(fa[i]) printf("%d %d\n",i,fa[i]);

    return 0;

}

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

using namespace std;

const int maxn=1e5+10;

struct edge{int v,nxt;}e[maxn<<1];

int head[maxn],ecnt=0;

void add(int u,int v)

{

	e[++ecnt]=(edge){v,head[u]},head[u]=ecnt;

	e[++ecnt]=(edge){u,head[v]},head[v]=ecnt;

}

struct data

{

	long long D;

	int id;

	bool operator < (const data &b){return D<b.D;}

}c[maxn];

int fa[maxn],siz[maxn],n,rt;

int find(int lim,long long x)

{

	int l=1,r=lim,ans=0;

	while(l<=r)

	{

		int mid=l+r>>1;

		if(c[mid].D>=x)r=mid-1,ans=mid;

		else l=mid+1;

	}

//	cout<<c[ans].D<<endl;

//	if(c[ans].D!=x)printf("fuckyou\n");

	return ans;

}

int dep[maxn];

long long tot=0;

void dfs(int u,int pre)

{

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

	tot+=dep[u]-1;

	for(int i=head[u];~i;i=e[i].nxt)

	{

		int v=e[i].v;

		if(v==pre)continue;

		dfs(v,u);

	}

}

int main()

{

	memset(head,-1,sizeof(head));

	scanf("%d",&n);

	for(int i=1;i<=n;i++)scanf("%lld",&c[i].D),c[i].id=i;

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

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

	{

		siz[i]++;

		int p=find(i-1,c[i].D-(n-2*1LL*siz[i]));

		if(c[i].D-(n-2*1LL*siz[i])!=c[p].D)

		{

			printf("-1\n");

			return 0;

		}

		siz[p]+=siz[i];

		fa[c[i].id]=c[p].id;

	}

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

	if(fa[i])add(fa[i],i);

	else rt=i;

	dfs(rt,0);

	if(tot!=c[1].D)

	{

		printf("-1\n");

		return 0;

	}

	for(int i=1;i<=n;i++)if(fa[i])printf("%d %d\n",fa[i],i);

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

#include <cstdlib>

#include <cstring>

#include <cmath>

#include <iostream>

#include <algorithm>

#include <vector>

#include <set>

#include <map>

#include <stack>

#include <queue>

#define rep(i,l,r) for(int i=(l);i<=(r);++i)

#define per(i,r,l) for(int i=(r);i>=(l);--i)

using namespace std;

typedef long long ll;

const int maxn=1e5+10;

int n,sz[maxn],fa[maxn],d[maxn];

ll b[maxn],D;

vector<int> G[maxn];

struct Node{ll x;int id;}a[maxn];

inline bool operator <(Node x,Node y){return x.x<y.x;}

void dfs(int u,int fa){

    for(int v:G[u]) if(v!=fa) d[v]=d[u]+1,dfs(v,u);

}

int main(){

    scanf("%d",&n);

    rep(i,1,n) scanf("%lld",&a[i].x),a[i].id=i,b[i]=a[i].x;

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

    rep(i,1,n) sz[i]=1;

    per(i,n,2){

        int u=a[i].id;

        if(n%2==0&&sz[u]==n/2) return puts("-1"),0;

        int x=lower_bound(b+1,b+n+1,a[i].x-(n-2*sz[u]))-b;

        if(b[x]!=a[i].x-(n-sz[u])+sz[u]) return puts("-1"),0;

        x=a[x].id;fa[u]=x;sz[x]+=sz[u];

    }

    rep(i,1,n) G[i].push_back(fa[i]),G[fa[i]].push_back(i);

    dfs(a[1].id,0);

    rep(i,1,n) D+=d[i];if(D!=a[1].x) return puts("-1"),0; 

    rep(i,1,n) if(fa[i]) printf("%d %d\n",i,fa[i]);

    return 0;

}

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

#include <cstdio>

#include <cstring>

#include <iostream>

#include <algorithm>

using namespace std;

#define ll long long

#define N 100005

#define M 200005

map<ll, int>p;

map<ll, int>::iterator it;

int fat[N], siz[N], a[N], b[N], fir[N], nex[M], tar[M];

int n, cnt;

void Add(int a, int b)

{

	++cnt;

	tar[cnt] = b;

	nex[cnt] = fir[a];

	fir[a] = cnt;

}

ll wd[N], d[N];

void Dfs(int x, int dis)

{

    siz[x] = 1;

    d[1] += dis;

	for (int i = fir[x]; i; i = nex[i])

    {

		if (tar[i] != fat[x])

		{

			fat[tar[i]] = x;

			Dfs(tar[i], dis + 1);

			siz[x] += siz[tar[i]];

        }

    }

}

void Dfs(int x)

{

	for (int i = fir[x]; i; i = nex[i])

	{

		if (tar[i] != fat[x])

        {

            d[tar[i]] = d[x] + n - siz[tar[i]] * 2;

            Dfs(tar[i]);

        }

    }

}

int Getbel(int x)

{

	if (fat[x] == x)

		return x;

	return fat[x] = Getbel(fat[x]);

}

int main()

{

	scanf("%d",&n);

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

	{

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

		p[wd[i]] = i;

	}

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

	{

		fat[i] = i;

		siz[i] = 1;

	}

	it = p.end();

	for (it--; it != p.begin(); it--)

	{

		if (n - siz[it -> second] * 2 == 0 || !p.count(it -> first - (n - siz[it -> second] * 2)))

		{

			puts("-1");

			return 0;

		}

		cnt++;

		a[cnt] = it -> second;

		b[cnt] = p[it -> first - (n - siz[it -> second] * 2)];

		siz[fat[a[cnt]] = Getbel(b[cnt])] += siz[a[cnt]];

	}

	cnt = 0;

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

	{

		Add(a[i], b[i]);

		Add(b[i], a[i]);

	}

	fat[1] = 0;

	Dfs(1, 0);

	Dfs(1);

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

	{

		if (wd[i] != d[i])

		{

			puts("-1");

		    return 0;

		}

	}

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

		printf("%d %d\n", a[i], b[i]);

}