stablegradients/pie-gem5-pairs huggingface dataset:
// Slower C++ solution:
#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;

}


// Faster C++ solution for the same problem (measured speedup: 18.549421985584274x):
#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;

}
// 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() {

	ios::sync_with_stdio(false);

	cin.tie(0);

	cout.tie(0);

	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.582781671465766x):
#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;

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



using namespace std;



#define int long long

#define size(x) ((int) x.size())

typedef pair<int,int> pii;



const int MAXN = 1e5 + 5;



int n, root, cnt;

int a[MAXN];

int d[MAXN], sz[MAXN];

int v, par;



vector<int> adj[MAXN];

vector<pii> ans;



pii b[MAXN];



bool cmp(int i, int j) {

	return d[i] > d[j];

}



int getP(int i) {

	int hp = d[i] - n + 2 * sz[i];

	auto tmp = lower_bound(b, b + n, pii(hp, 0)) - b;

	//cerr << b[tmp].first << " " << b[tmp].second << endl;

	if (b[tmp].first != hp) 

		return -1;

	return b[tmp].second;

}



int dfs(int u) {

	int val = 0;

	for (auto v : adj[u])

		val += dfs(v) + sz[v];

	return val;

}

	

int32_t main() {

	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

	cin >> n;

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

		cin >> d[i];

		b[i] = {d[i], i};

		a[i] = i;

		sz[i] = 1;

	}

	sort(b, b + n);

	sort(a, a + n, cmp);

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

		v = a[i];

		par = getP(v);

		//cout << v << " " << par << endl;

		if (par == -1)

			return cout << -1 << endl, 0;

		sz[par] += sz[v];

		ans.push_back({v, par}); 

		adj[par].push_back(v);

		if (2 * sz[v] > n) 

			return cout << -1 << endl, 0;

		//cout << v << " " << par << endl;

	}

	root = a[n - 1];

	if (d[root] != dfs(root))

		return cout << -1 << endl, 0;

	for (auto x : ans) 

		cout << x.first + 1 << " " << x.second + 1 << endl;

	return 0;

}

// Faster C++ solution for the same problem (measured speedup: 3.5768674125701194x):
#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;

}
// 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() {

	ios::sync_with_stdio(false);

	cin.tie(0);

	cout.tie(0);

	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.595090648320161x):
#include<bits/stdc++.h>

#define rep(X,A,B) for(int X=A;X<=B;X++)

#define tep(X,A,B) for(int X=A;X>=B;X--)

#define LL long long

#define DB double

const int N=400010;

const int M=800010;

using namespace std;



int n;

map<LL,int> mp;

LL sz[N];

int fa[N],edge[M],lst[N],nxt[M],t=0;



struct nn{

	LL d;

	int id;

}a[N];



int cmp(nn A,nn B){

	return A.d<B.d;

}



void READ(){

	scanf("%d",&n);

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

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

}



void ADD(int x,int y){

	edge[++t]=y;nxt[t]=lst[x];lst[x]=t;

}



LL SEARCH(int x,int dep){

	LL res=dep;

	for(int r=lst[x];r;r=nxt[r]){

		res+=SEARCH(edge[r],dep+1);

	}

	return res;

}



int SOLVE(){

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

	tep(i,n,2){

		int x=a[i].id;

		LL d=a[i].d;

		LL now=d+2*sz[x]-n;

		int pos=mp[now];

		if(pos==0||now>=a[i].d)return 0;

		fa[x]=pos;

		ADD(fa[x],x);

		sz[fa[x]]+=sz[x];

	}

	LL sum=SEARCH(a[1].id,0);

	if(sum!=a[1].d)return 0;

	rep(i,1,n){

		if(i==a[1].id)continue;

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

	}

	return 1;

}



int main(){

	READ();

	if(!SOLVE())printf("-1\n");

	return 0;

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



using namespace std;



#define int long long

#define size(x) ((int) x.size())

typedef pair<int,int> pii;



const int MAXN = 1e5 + 5;



int n, root, cnt;

int a[MAXN];

int d[MAXN], sz[MAXN];

int v, par;



vector<int> adj[MAXN];

vector<pii> ans;



pii b[MAXN];



bool cmp(int i, int j) {

	return d[i] > d[j];

}



int getP(int i) {

	int hp = d[i] - n + 2 * sz[i];

	auto tmp = lower_bound(b, b + n, pii(hp, 0)) - b;

	//cerr << b[tmp].first << " " << b[tmp].second << endl;

	if (b[tmp].first != hp) 

		return -1;

	return b[tmp].second;

}



int dfs(int u) {

	int val = 0;

	for (auto v : adj[u])

		val += dfs(v) + sz[v];

	return val;

}

	

int32_t main() {

	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

	cin >> n;

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

		cin >> d[i];

		b[i] = {d[i], i};

		a[i] = i;

		sz[i] = 1;

	}

	sort(b, b + n);

	sort(a, a + n, cmp);

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

		v = a[i];

		par = getP(v);

		//cout << v << " " << par << endl;

		if (par == -1)

			return cout << -1 << endl, 0;

		sz[par] += sz[v];

		ans.push_back({v, par}); 

		adj[par].push_back(v);

		if (2 * sz[v] > n) 

			return cout << -1 << endl, 0;

		//cout << v << " " << par << endl;

	}

	root = a[n - 1];

	if (d[root] != dfs(root))

		return cout << -1 << endl, 0;

	for (auto x : ans) 

		cout << x.first + 1 << " " << x.second + 1 << endl;

	return 0;

}

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

#define rep(X,A,B) for(int X=A;X<=B;X++)

#define tep(X,A,B) for(int X=A;X>=B;X--)

#define LL long long

#define DB double

const int N=400010;

const int M=800010;

using namespace std;



int n;

map<LL,int> mp;

LL sz[N];

int fa[N],edge[M],lst[N],nxt[M],t=0;



struct nn{

	LL d;

	int id;

}a[N];



int cmp(nn A,nn B){

	return A.d<B.d;

}



void READ(){

	scanf("%d",&n);

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

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

}



void ADD(int x,int y){

	edge[++t]=y;nxt[t]=lst[x];lst[x]=t;

}



LL SEARCH(int x,int dep){

	LL res=dep;

	for(int r=lst[x];r;r=nxt[r]){

		res+=SEARCH(edge[r],dep+1);

	}

	return res;

}



int SOLVE(){

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

	tep(i,n,2){

		int x=a[i].id;

		LL d=a[i].d;

		LL now=d+2*sz[x]-n;

		int pos=mp[now];

		if(pos==0||now>=a[i].d)return 0;

		fa[x]=pos;

		ADD(fa[x],x);

		sz[fa[x]]+=sz[x];

	}

	LL sum=SEARCH(a[1].id,0);

	if(sum!=a[1].d)return 0;

	rep(i,1,n){

		if(i==a[1].id)continue;

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

	}

	return 1;

}



int main(){

	READ();

	if(!SOLVE())printf("-1\n");

	return 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() {

	ios::sync_with_stdio(false);

	cin.tie(0);

	cout.tie(0);

	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: 2.539198777860938x):
#include <bits/stdc++.h>



using namespace std;



const int maxn = 100010;



typedef long long ll;



priority_queue<ll> pq;

map<ll, int> mp;



int n, l[maxn], dep[maxn], sz[maxn], w[maxn], vis[maxn], e_u[maxn], e_v[maxn], tot, e = 0;

ll D[maxn], S[maxn];



struct Edge {

    int v, x;

} E[maxn];



inline void addEdge(int u, int v) {

    E[e].v = v; E[e].x = l[u]; l[u] = e++;

}



void dfs1(int u) {

    sz[u] = 1;

    for (int p = l[u]; p >= 0; p = E[p].x) {

        int v = E[p].v;

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

        dfs1(v);

        sz[u] += sz[v];

    }

}



void dfs2(int u) {

    for (int p = l[u]; p >= 0; p = E[p].x) {

        int v = E[p].v;

        S[v] = S[u] + n - 2 * sz[v];

        dfs2(v);

    }

}



int main() {

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

    scanf("%d", &n);

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

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

        mp[D[i]] = i;

        pq.push(D[i]);

        w[i] = 1;

    }

    vis[0] = 1;

    while (pq.size() > 1) {

        ll v = pq.top(); pq.pop();

        int u = mp[v];

        vis[u] = 1;

        if (!vis[mp[v + 2 * w[u] - n]]) {

            int t = mp[v + 2 * w[u] - n];

            w[t] += w[u];

            addEdge(t, u);

            ++ tot;

            e_u[tot] = t; e_v[tot] = u;

        } else {

            puts("-1");

            return 0;

        }

    }

    int r = mp[pq.top()];

    dfs1(r);

    for (int i = 1; i <= n; i++) S[r] += dep[i];

    dfs2(r);

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

        if (S[i] != D[i]) {

            puts("-1");

            return 0;

        }

    }

    for (int i = 1; i <= tot; i++) printf("%d %d\n", e_u[i], e_v[i]);

    return 0;

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

using namespace std;



const int N = 100010;



typedef long long LL;



LL D[N]; int id[N], sz[N];

map<LL, int> mp;



inline void Fuck() {

	puts("-1"), exit(0);

}



vector<int> G[N];



inline void adde(int from, int to) {

	G[from].push_back(to), G[to].push_back(from);

}



LL dfs(int u, int f) {

	LL res = 0;

	for (auto v : G[u]) if (v != f) 

		res += dfs(v, u) + sz[v];

	return res;

}



int main() {

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

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

	sort(id + 1, id + n + 1, [](int a, int b){return D[a] > D[b];});

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

		int v = id[i];

		LL tmp = D[v] - n + sz[v] * 2;

		if (!mp.count(tmp) || tmp >= D[v]) Fuck();

		adde(v, mp[tmp]), sz[mp[tmp]] += sz[v];

	}

	if (dfs(id[n], 0) != D[id[n]]) Fuck();

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

		for (auto v : G[i]) if (v > i) printf("%d %d\n", i, v);

}

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



using namespace std;



const int maxn = 100010;



typedef long long ll;



priority_queue<ll> pq;

map<ll, int> mp;



int n, l[maxn], dep[maxn], sz[maxn], w[maxn], vis[maxn], e_u[maxn], e_v[maxn], tot, e = 0;

ll D[maxn], S[maxn];



struct Edge {

    int v, x;

} E[maxn];



inline void addEdge(int u, int v) {

    E[e].v = v; E[e].x = l[u]; l[u] = e++;

}



void dfs1(int u) {

    sz[u] = 1;

    for (int p = l[u]; p >= 0; p = E[p].x) {

        int v = E[p].v;

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

        dfs1(v);

        sz[u] += sz[v];

    }

}



void dfs2(int u) {

    for (int p = l[u]; p >= 0; p = E[p].x) {

        int v = E[p].v;

        S[v] = S[u] + n - 2 * sz[v];

        dfs2(v);

    }

}



int main() {

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

    scanf("%d", &n);

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

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

        mp[D[i]] = i;

        pq.push(D[i]);

        w[i] = 1;

    }

    vis[0] = 1;

    while (pq.size() > 1) {

        ll v = pq.top(); pq.pop();

        int u = mp[v];

        vis[u] = 1;

        if (!vis[mp[v + 2 * w[u] - n]]) {

            int t = mp[v + 2 * w[u] - n];

            w[t] += w[u];

            addEdge(t, u);

            ++ tot;

            e_u[tot] = t; e_v[tot] = u;

        } else {

            puts("-1");

            return 0;

        }

    }

    int r = mp[pq.top()];

    dfs1(r);

    for (int i = 1; i <= n; i++) S[r] += dep[i];

    dfs2(r);

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

        if (S[i] != D[i]) {

            puts("-1");

            return 0;

        }

    }

    for (int i = 1; i <= tot; i++) printf("%d %d\n", e_u[i], e_v[i]);

    return 0;

}
// 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.1070092982444446x):
#include<cstdio>

#include<map>

#include<algorithm>

using namespace std;

typedef long long LL;

const int maxn=1e5+2;

int n;

map<LL,int> mp;

LL dis[maxn];

int id[maxn],fa[maxn],siz[maxn];

bool cmp(int x,int y){

	return dis[x]>dis[y];

}

int main(){

	scanf("%d",&n);

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

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

		siz[i]=1;

		id[i]=mp[dis[i]]=i;

	}

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

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

		fa[id[i]]=mp[dis[id[i]]-n+2*siz[id[i]]];

		if (!fa[id[i]]){

			puts("-1");

			return 0;

		}

		siz[fa[id[i]]]+=siz[id[i]];

	}

	for (int i=1;i<n;i++) dis[id[n]]-=siz[id[i]];

	if (dis[id[n]]){

		puts("-1");

		return 0;

	}

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

	return 0;

}