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

}

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

}

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

}

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

}

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

}

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

}

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

}


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

}

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

}

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

}

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

}

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

}

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

}

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

}

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

#include <cstdio>

#include <vector>

#include <algorithm>

using namespace std;



typedef long long ll;



const int MAXN = 100000;



vector<int>G[MAXN + 5];

map<ll, int>mp;



int siz[MAXN + 5];



ll check(int x) {

	ll ret = 0;

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

		int to = G[x][i];

		ret += check(to) + siz[to];

	}

	return ret;

}



int main() {

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

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

		ll D; scanf("%lld", &D);

		mp[D] = i, siz[i] = 1;

	}

	map<ll, int>::reverse_iterator rt;

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

		if( siz[it->second] == n ) {

			rt = it;

			break;

		}

		int x = it->second;

		ll k = it->first + siz[x] - (n - siz[x]);

		if( k < it->first && mp.count(k) ) {

			int p = mp[k];

			siz[p] += siz[x];

			G[p].push_back(x);

		}

		else {

			puts("-1");

			return 0;

		}

	}

	if( check(rt->second) == rt->first ) {

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

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

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

		}

	}

	else puts("-1");

}

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

}

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

using namespace std;

const int MAXN = 1234567;

char s[MAXN];

int f[MAXN];

int nxt[MAXN],prv[MAXN];

int main()

{

    int n;

    scanf("%d", &n);

    scanf("%s", s);

    memset(f,0,sizeof(f));

    nxt[n] = n;

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

    {

        if(s[i] == '0')

            nxt[i] = i;

        else

            nxt[i] = nxt[i+1];

    }

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

    {

        if(s[i] == '0')

            prv[i] = i;

        else

            prv[i] = (i==0?-1:prv[i-1]);

    }

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

    {

        if(i >= 3 && s[i-1] == '1' && s[i-2] == '0' && s[i-3] == '1')

        {

            int j = prv[i-3];

            f[i] = max(f[i],f[j+1]+(i-j-3));

            if(j != i-4)

                f[i] = max(f[i],f[j+2]+(i-j-4));

        }

        if(i == n)

            break;

        if(i+3 <= n && s[i] == '1' && s[i+1] == '0' && s[i+2] == '1')

        {

            int j = nxt[i+2];

            f[j] = max(f[j],f[i]+(j-i-2));

            if(j != i+3)

                f[j-1] = max(f[j-1],f[i]+(j-i-3));

        }

        f[i+1] = max(f[i+1],f[i]);

    }

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

    return 0;

}

// Optimized solution to the same problem (faster):
#include<cstring>

#include<algorithm>

#include<cmath>

#include<iostream>

#include<cstdio>

using namespace std;

typedef long long ll;

const int maxm=500007;

char s[maxm];

int n;

int dp[maxm];//到i位置的最大操作数 

int l[maxm];//在左边离i最近的0的位置 

int main()

{

 scanf("%d",&n);

 scanf("%s",s+1);

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

 {

  if(s[i]=='1') l[i]=l[i-1];

  else l[i]=i;	

 }

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

 {

   dp[i]=dp[i-1];

   if(s[i]=='1')

   {

     if(s[i-1]=='0'&&s[i-2]=='1')

     {

       dp[i]=max(dp[i],dp[l[i-2]]+i-l[i-2]-2);//100|11111101的贡献为他们的长度-2,

       dp[i]=max(dp[i],dp[l[i-2]+1]+i-l[i-2]-1-2);//11111101|11111101

     }

     else if(l[i]>1&&s[l[i]-1]=='1')

	 {

	  dp[i]=max(dp[i],dp[l[i]-2]+i-l[i]+2-2);//101111111

     }

   }

 }

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

 return 0;	

}

// Fastest known solution for this problem: