思路:从后往前操作,贪心的合并,使得合并后的新集合尽量小,编号 i 操作最多判定 n2÷i 的量级种连边。
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
int a[1000009];
int fa[1000009];
int dx[1000009];
int getfa(int a){
if(fa[a]==a){
return a;
}
return fa[a]=getfa(fa[a]);
}
void merge(int x,int y){
if(getfa(x)!=getfa(y))
dx[getfa(y)]+=dx[getfa(x)];
fa[getfa(x)]=getfa(y);
}
int n;
struct st{
int v,ne;
}sd[1000009];
int inn;
int h[1000009];
void cr(){
for(int i=0;i<=n+10;i++){
h[i]=0;
}
inn=0;
}
void add(int u,int v){
sd[++inn].v=v;
sd[inn].ne=h[u];
h[u]=inn;
}
pii an[1000009];
void _main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=0;i<=n+10;i++){
fa[i]=i,dx[i]=1;
an[i]={0,0};
}
for(int i=n-1;i>=1;i--){
cr();
int sx;
sx=(n+1)*(n+1)/i+1000;
for(int j=1;j<=n;j++){
for(int k=h[a[j]%i];k;k=sd[k].ne){
if(getfa(sd[k].v)!=getfa(j)){
if(an[i].first==0||dx[getfa(an[i].first)]+dx[getfa(an[i].second)]>dx[getfa(sd[k].v)]+dx[getfa(j)]){
//cout<<sd[k].v<<"-"<<j<<endl;
an[i]={sd[k].v,j};
}
}
sx--;
if(sx<0){
break;
}
}
if(sx<0){
merge(an[i].first,an[i].second);
//cout<<an[i].first<<" "<<an[i].second<<" "<<(getfa(an[i].first)!=getfa(an[i].second))<<endl;
break;
}
add(a[j]%i,j);
}
if((getfa(an[i].first)!=getfa(an[i].second)))
merge(an[i].first,an[i].second);
}
cout<<"YES"<<endl;
for(int i=1;i<n;i++){
cout<<an[i].first<<" "<<an[i].second<<endl;
}
}
signed main(){
int t;
cin>>t;
while(t--){
_main();
}
return 0;
}