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



using namespace std;



#define int long long



typedef pair<int,int> pii;



const int N = 1e5 + 100;



int d[N], sz[N], a[N];

vector<int> adj[N];

vector<pii> ans;

pii b[N];

int n, mx, val;



bool cmp(int x, int y) {

	return d[x] > d[y];	

}



inline int getPar(int v) {

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

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

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

		cout << -1;

		exit(0);

	}

	return b[tmp].second;

}



int dfs(int v) {

	int res = 0;

	for (auto u : adj[v])

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

	return res;

}



int32_t main() {

	ios_base::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++) {

		int v = a[i];

		int p = getPar(v);

		sz[p] += sz[v];

		ans.push_back({v, p});

		adj[p].push_back(v);

		if (2 * sz[v] > n)

			return cout << -1, 0;

	}

	int root = a[n - 1];

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

		return cout << -1, 0;

	for (auto e : ans)

		cout << e.first + 1 << " " << e.second + 1 << '\n', 0;

}

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

using namespace std;

const int N=100005;

int main()

{

	ios::sync_with_stdio(false);

	int n;

	cin>>n;

	vector<pair<long long,int>>e;

	map<long long,int>ret;

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

	{

		long long x;

		cin>>x;

		ret[x]=i;

		e.push_back({x,i});

	}

	sort(e.rbegin(),e.rend());

	long long x=e.back().first;

	vector<int>sz(n,1);

	vector<long long>dp(n,0);

	vector<pair<int,int>>ans;

	for(auto c:e)

	{

		if(c.first!=x)

		{

			if(sz[c.second]*2>=n)

			{

				cout<<-1<<endl;

				return 0;

			}

			long long need=c.first-(n-2*sz[c.second]);

			if(!ret.count(need))

			{

				cout<<-1<<endl;

				return 0;

			}

			int par=ret[need];

			dp[par]+=dp[c.second]+sz[c.second];

			sz[par]+=sz[c.second];

			ans.push_back({c.second+1,par+1}); 

		}

	}

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

	{

		cout<<-1<<endl;

		return 0;

	}

	for(auto c:ans)

		cout<<c.first<<' '<<c.second<<endl;

	return 0;

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

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

#include<map>

#include<vector>

#define pb push_back



typedef long long LL;



const int N=100005;



int n,size[N],id[N],ans1[N],ans2[N];

LL tot,a[N];

std::map<LL,int> num;

std::vector<int> vec[N];



bool cmp(int x,int y)

{

	return a[x]>a[y];

}



void dfs(int x,int fa,int d)

{

	tot+=(LL)d;

	for (int i=0;i<vec[x].size();i++)

		if (vec[x][i]!=fa) dfs(vec[x][i],x,d+1);

}



int main()

{

	scanf("%d",&n);

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

	for (int i=1;i<=n;i++) size[i]=1,id[i]=i;

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

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

	{

		int x=id[i];LL w=a[x]-(n-size[x])+size[x];

		if (!num[w]||w>=a[x]) {puts("-1");return 0;}

		int y=num[w];

		ans1[i]=x;ans2[i]=y;

		vec[x].pb(y);vec[y].pb(x);

		size[y]+=size[x];

	}

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

	if (tot!=a[id[n]]) {puts("-1");return 0;}

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

	return 0;

}

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

using namespace std;

const int N=100005;

int main()

{

	ios::sync_with_stdio(false);

	int n;

	cin>>n;

	vector<pair<long long,int>>e;

	map<long long,int>ret;

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

	{

		long long x;

		cin>>x;

		ret[x]=i;

		e.push_back({x,i});

	}

	sort(e.rbegin(),e.rend());

	long long x=e.back().first;

	vector<int>sz(n,1);

	vector<long long>dp(n,0);

	vector<pair<int,int>>ans;

	for(auto c:e)

	{

		if(c.first!=x)

		{

			if(sz[c.second]*2>=n)

			{

				cout<<-1<<endl;

				return 0;

			}

			long long need=c.first-(n-2*sz[c.second]);

			if(!ret.count(need))

			{

				cout<<-1<<endl;

				return 0;

			}

			int par=ret[need];

			dp[par]+=dp[c.second]+sz[c.second];

			sz[par]+=sz[c.second];

			ans.push_back({c.second+1,par+1}); 

		}

	}

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

	{

		cout<<-1<<endl;

		return 0;

	}

	for(auto c:ans)

		cout<<c.first<<' '<<c.second<<endl;

	return 0;

}
// Slower C++ solution:
// In the name of God



#include<bits/stdc++.h>



#define F first

#define S second

#define PB push_back

#define sz(s) int((s).size())

#define bit(n,k) (((n)>>(k))&1)



using namespace std;



typedef long long ll;

typedef pair<int,int> pii;

typedef pair<ll,ll> pll;



const int maxn=1e5+10,mod=1e9+7;

const ll inf=1e18;



pair<ll,int> p[maxn];

map<ll,vector<int> >mp;

int par[maxn],SZ[maxn];

vector<int>v[maxn];



pair<ll,int> dfs(int u,int par=-1){

    ll A=0;

    int B=1;

    for(int y:v[u]){

	if(y!=par){

	    pair<ll,int>p=dfs(y,u);

	    B+=p.S;

	    A+=p.F+p.S;

	}

    }

    return {A,B};

}



int main(){

    int n;cin>>n;

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

	cin>>p[i].F;

	p[i].S=i;

    }

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

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

	SZ[p[i].S]=1;

	if(mp.count(p[i].F)){

	    for(int id:mp[p[i].F]){

		par[id]=p[i].S;

		SZ[p[i].S]+=SZ[id];

	    }

	    mp.erase(p[i].F);

	}

	mp[p[i].F+2*SZ[p[i].S]-n].PB(p[i].S);

    }

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

	if(par[i]==0 && i!=p[1].S){

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

	}

	else if(par[i]!=0){

	    v[par[i]].PB(i);

	}

    }

    if(dfs(p[1].S).F!=p[1].F){

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

    }

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

	if(i==p[1].S)continue;

	cout<<i<<" "<<par[i]<<"\n";

    }

    return 0;

}


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

#include <iostream>

#include <vector>

#include <map>

using namespace std;

typedef long long ll;



const int MAXN = 1e5 + 10;

vector<pair<int, int> > edg;

pair<ll, int> d[MAXN];

vector<int> Mat[MAXN];

int n, cnt[MAXN];

map<ll, int> mp;

bool se[MAXN];

ll dist, dt;

int num;



void dfs(int v, int di) {

	se[v] = 1, num++;

	dist += di;

	for (int i = 0; i < Mat[v].size(); i++)

		if (!se[Mat[v][i]])

			dfs(Mat[v][i], di + 1);

}



int main() {

	cin >> n;

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

		cin >> d[i - 1].first;

		if (i == 1)

			dt = d[i - 1].first;

		mp[d[i - 1].first] = i;

		d[i - 1].second = i;

		cnt[i] = 1;

	}

	sort(d, d + n);

	reverse(d, d + n);

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

		int k = cnt[d[i].second];

		if (2 * k > n || mp.find(d[i].first + k - (n - k)) == mp.end())

			return cout << -1, 0;

		cnt[mp[d[i].first + k - (n - k)]] += k;

		edg.push_back({d[i].second, mp[d[i].first + k - (n - k)]});

		Mat[mp[d[i].first + k - (n - k)]].push_back(d[i].second);

		Mat[d[i].second].push_back(mp[d[i].first + k - (n - k)]);

	}

	dfs(1, 0);

	if (dist == dt && num == n && edg.size() == n - 1) {

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

			cout << edg[i].first << ' ' << edg[i].second << endl;

		return 0;

	}

	cout << -1;

}

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



#define int long long



typedef pair<int,int> pii;



const int N = 1e5 + 100;



int d[N], sz[N], a[N];

vector<int> adj[N];

vector<pii> ans;

pii b[N];

int n, mx, val;



bool cmp(int x, int y) {

	return d[x] > d[y];	

}



inline int getPar(int v) {

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

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

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

		cout << -1;

		exit(0);

	}

	return b[tmp].second;

}



int dfs(int v) {

	int res = 0;

	for (auto u : adj[v])

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

	return res;

}



int32_t main() {

	ios_base::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++) {

		int v = a[i];

		int p = getPar(v);

		sz[p] += sz[v];

		ans.push_back({v, p});

		adj[p].push_back(v);

		if (2 * sz[v] > n)

			return cout << -1, 0;

	}

	int root = a[n - 1];

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

		return cout << -1, 0;

	for (auto e : ans)

		cout << e.first + 1 << " " << e.second + 1 << '\n', 0;

}

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

#include<cstdio>

#include<cstdlib>

#include<cstring>

#include<algorithm>

#include<map>

#include<vector>

#define pb push_back



typedef long long LL;



const int N=100005;



int n,size[N],id[N],ans1[N],ans2[N];

LL tot,a[N];

std::map<LL,int> num;

std::vector<int> vec[N];



bool cmp(int x,int y)

{

	return a[x]>a[y];

}



void dfs(int x,int fa,int d)

{

	tot+=(LL)d;

	for (int i=0;i<vec[x].size();i++)

		if (vec[x][i]!=fa) dfs(vec[x][i],x,d+1);

}



int main()

{

	scanf("%d",&n);

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

	for (int i=1;i<=n;i++) size[i]=1,id[i]=i;

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

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

	{

		int x=id[i];LL w=a[x]-(n-size[x])+size[x];

		if (!num[w]||w>=a[x]) {puts("-1");return 0;}

		int y=num[w];

		ans1[i]=x;ans2[i]=y;

		vec[x].pb(y);vec[y].pb(x);

		size[y]+=size[x];

	}

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

	if (tot!=a[id[n]]) {puts("-1");return 0;}

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

	return 0;

}

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

}
// 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.810539018286689x):
#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;

}
// 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.7987950156106494x):
#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;

}